Отношение реализации интерфейса C# - это просто отношение" Can-Do"?

сегодня кто-то сказал мне, что реализация интерфейса в C#-это просто отношения "Can-Do", а не отношения "Is-A". Это противоречит моей давней вере в LSP (принцип замены Лискова). Я всегда думаю, что все наследование должно означать отношения" Есть-Есть".

Итак, если реализация интерфейса-это просто отношение "Can-Do". Зачем, если есть интерфейс "IHuman" и "IEngineer", и один класс "программист" наследует от "IHuman" & "IEngineer"? Конечно, "Программист" - это" IHuman "и"IEngineer".

Если это просто отношение "может-сделать", означает ли это, что мы не можем ожидать, что поведение экземпляра" программиста " может отличаться между тем, когда его рассматривают как IHuman и рассматривают как IEngineer?

5 ответов


по моему опыту, не очень-то помогает думать об отношениях "есть-А" и "может-делать". Вы быстро попадаете в проблемы. Это несоответствие импеданса между реальным миром и OO, в основном. Как бы много люди ни говорили о моделировании реального мира, вам принципиально необходимо понять, что означают отношения между типами на платформе, которую вы используете.

иногда интерфейсы могут использоваться в качестве возможностей, а иногда они могут представлять собой более нормальный отношения" это-а". Я бы не слишком зациклился на этом - просто убедитесь, что вы понимаете, что они могут делать, а что нет.--1-->


Я склонен думать об интерфейсах как о договоре поведения. Классические примеры таких интерфейсов, как IComparable и IEnumerable.

в приведенном вами примере IHuman и IEngineer на самом деле не являются поведением.


нашел этот вопрос довольно поздно, но я хотел вмешаться.

интерфейсы В C# имеют отношение is-a, но не is-an-object. Скорее, это-реализация.

другими словами, для класса Foo, который реализует IBar, следующий тест:

Foo myFoo = new Foo(); 
return myFoo is IBar;

буквально возвращает true. Вы также можете сказать,

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, имеет отношение can-do, а также отношение is-a, так же, как и интерфейс. Просто его реализация была заранее для него построена.

настоящий вопрос в том, есть-а -что, can-do -что? Наследуемый объект класса-a -[Родительский экземпляр] и может-сделать-[поведение родителей], тогда как реализация интерфейса-an -[реализация интерфейса] и поэтому can-do -[поведение интерфейса].

в большинстве случаев, когда используются программные отношения is-a, такие как перечисленные выше, оценивается только интерфейс, поэтому как унаследованный класс, так и реализованный интерфейс имеют одинаковые качества is-a и can-do.

HTH, Джон!--5-->


разработчики .NET framework используют интерфейсы для обозначения отношения" имеет "(или" может делать"), тогда как" является " реализуется с помощью наследования.

обоснование этого можно найти в выбор между классами и интерфейсами раздел руководства разработчика .NET Framework:

интерфейс определяет подписи для набора членов, которые должны предоставить разработчики. Интерфейсы не могут предоставить сведения о реализации член.

Итак, поскольку ваши классы примеров" программист "и" инженер", скорее всего, будут иметь свои собственные функциональные возможности, они будут более подходяще реализованы с использованием наследования.


на самом деле именно поэтому большинство интерфейсов-это возможности, а не имена, поэтому у вас есть

IComparable, ITestable, IEnumerable

и

человека, животное, Собака, и т. д.

в любом случае, как уже упоминалось, вы должны быть прагматичными, у меня есть общее правило, когда я кодирую: никогда не позволяйте концепциям, конвенциям или стандартной практике встать на путь выполнения работы, лучше быть прагматичными, чем академический.

поэтому, если вы уверены, что интерфейсы действительно лучше подходят вашему дизайну, идите на это, не беспокойтесь о таком вопросе, как этот.