Сегодня кто-то сказал мне, что реализация интерфейса в C# - это просто взаимосвязь «Может-Делать», а не «Есть-А». Это противоречит моей давней вере в LSP (принцип замещения Лискова). Я всегда думаю, что всякое наследование должно означать отношения «есть-А».
Итак, реализация интерфейса If - это просто связь «Можно-Сделать». Что, если существует интерфейс «IHuman» и «IEngineer», а один класс «Programmer» наследуется от «IHuman» и «IEngineer»? Конечно, «программист» - это «человек» и «инженер-инженер».
Если это просто отношение «Can-Do», значит ли это, что мы не можем ожидать, что поведение экземпляра «Programmer» может отличаться при рассмотрении как IHuman и как IEngineer?





Я склонен думать об интерфейсах как о контракте поведения. Такие интерфейсы, как IComparable и IEnumerable, являются классическими примерами.
В приведенном вами примере IHuman и IEngineer на самом деле не являются поведениями.
По моему опыту, думать об отношениях «можно» и «можно сделать» не очень помогает. Вы быстро попадаете в проблемы. По сути, это несоответствие импеданса между реальным миром и объектно-ориентированным интерфейсом. Сколько бы люди ни говорили о моделировании реального мира, вам принципиально необходимо понимать, что означают отношения между типами на платформе, которую вы используете.
Иногда интерфейсы могут использоваться как возможности, а иногда они могут представлять собой более нормальные отношения «есть-а». Я бы не стал слишком зацикливаться на этом - просто убедитесь, что вы понимаете, что они могут делать, а что нет.
Что, если бы у вас был абстрактный класс только с абстрактными методами? Чем это будет отличаться от интерфейса? Я считаю, что нет никакой разницы, если только метод. Тогда почему Microsoft принесла две вещи. Какая реализация интерфейса?
@ Sudhir.net: Я стараюсь избегать разговоров об отношениях типа «есть-а» и т. д., Как я отметил в первом предложении. Абстрактный класс только с абстрактными методами отличается от интерфейса различными деталями, такими как класс, который может быть производным только от одного другого класса, но может реализовывать несколько интерфейсов. Классы не могут объявлять универсальную дисперсию и всегда являются типами значений (тогда как интерфейсы также могут быть реализованы типами значений). Абстрактные классы легче развить, поскольку новые (не абстрактные) методы могут быть добавлены без нарушения существующих подклассов.
@Jon, у моего абстрактного класса есть только абстрагирование для всего цикла приложения. В будущем в абтрактном классе нет изменений, например, нет нескольких интерфейсов, нет полей, нет метода без абстрагирования. тогда чем отличается мой интерфейс.? Я хочу понять точку зрения реализации, что думают ребята из Microsoft?
@ Sudhir.net: Ну, это не похоже на то, чтобы C# был первым языком с таким разделением - для начала, он очень похож на абстрактные классы и интерфейсы в Java. Дело не в том, что ваш абстрактный класс реализует несколько интерфейсов, но если бы у вас был второй абстрактный класс, один класс не мог бы быть производным от обоих ваших абстрактных классов - но он мог реализует несколько интерфейсов. На самом деле, комментарии SO - не лучшее место для изучения различий - я предлагаю вам найти хорошую вводную книгу по C#.
@ Джон, это нормально. Но вчера у меня был разговор с кем-то, я рассказал все те вещи, о которых вы упомянули выше, но он сказал, что на основе отношений существует разница между абстрактным и интерфейсом, если абстрактный класс имеет только абстрактный метод, без множественного наследования, никаких других вещей.
@ Sudhir.net: Этот человек просто неправ. Когда вы говорите «нет множественного наследования», которое не определяется интерфейсом / абстрактным классом, оно определяется разработчиками / подклассами. Спросите этого человека, как бы он написал структуру, производную от вашего абстрактного класса ... В любом случае, как я уже сказал, это действительно не подходящее место для обсуждения. (Вы можете найти более конкретные вопросы о том, «в чем разница между абстрактным классом и интерфейсом».)
@Jon: я беру это понимание из этого обсуждения - причина, по которой Micorsoft привносит эти две концепции: Abstract - это суперкласс, также может иметь неабстрактный метод, поля. Интерфейс имеет цель множественного наследования. Это не имеет ничего общего с "is-a" и "can-do"
@ Sudhir.net: Извините, я несколько раз говорил, что это не место для этого. Я больше не буду здесь комментировать.
Разработчики платформы .NET используют интерфейсы для обозначения отношения «имеет» (или «может делать»), тогда как «является» реализуется с помощью наследования.
Обоснование этого можно найти в разделе Выбор между классами и интерфейсами Руководства разработчика .NET Framework:
An interface defines the signatures for a set of members that implementers must provide. Interfaces cannot provide implementation details for the members.
Итак, поскольку классы-примеры «Программист» и «Инженер», скорее всего, будут иметь свои собственные специфические функции, их было бы более подходящим образом реализовать с использованием наследования.
Собственно, поэтому большая часть интерфейса - это возможности, а не имена, поэтому у вас есть
IComparable, ITestable, IEnumerable
и
Человек, животное, собака и т. д.
В любом случае, как уже упоминалось, вы должны быть прагматичными, у меня есть общее правило, когда я кодирую: никогда не позволяйте концепциям, соглашениям или стандартным практикам мешать выполнению работы; лучше быть прагматичным, чем академическим.
Так что, если вы уверены, что интерфейсы действительно лучше подходят вашему дизайну, дерзайте, не беспокойтесь о таких вопросах, как этот.
Нашел этот вопрос довольно поздно, но я хотел вмешаться.
Интерфейсы в C# имеют отношение «есть-объект», но не «объект-объект». Скорее это реализация.
Другими словами, для класса Foo, реализующего IBar, следующий тест:
Foo myFoo = new Foo();
return myFoo is IBar;
буквально возвращает истину. Вы также можете сказать,
IBar bar = myArrayList[3] as IBar;
Foo foo = bar as Foo;
Или, если для метода требуется IBar, вы можете передать Foo.
void DoSomething(IBar bar) {
}
static void Main() {
Foo myFoo = new Foo();
DoSomething(myFoo);
}
Очевидно, что IBar сам по себе не имеет реализации, поэтому отношение «можно сделать» также применимо.
interface IBar { void happy(); }
class Foo : IBar
{
void happy()
{
Console.Write("OH MAN I AM SO HAPPY!");
}
}
class Program
{
static void Main()
{
IBar myBar = new Foo();
myBar.happy();
}
}
Но в этом отношении то же самое верно и для наследования объектов; объект класса Foo, который наследует класс Bar, имеет отношение «можно сделать», а также отношение «есть-есть», точно так же, как и интерфейс. Просто его реализация была заранее построена для этого.
Настоящий вопрос: а-какие, может-сделать-какие? Унаследованный объект класса - это -a-[родительский экземпляр] и can-do-[поведение родителей], тогда как реализация интерфейса-an-[реализация интерфейса] и, следовательно, can-do-[поведение интерфейса].
В большинстве случаев, когда используются программные отношения is-a, такие как перечисленные выше, оценивается только интерфейс, поэтому и унаследованный класс, и реализованный интерфейс имеют одинаковые качества is-a и can-do.
HTH, Джон
@Iain: Рад, что тебе это нравится. Отправьте мне отзыв, когда закончите :)