Когда использовать интерфейс вместо абстрактного класса и наоборот?


427

Это может быть общий вопрос ООП. Я хотел сделать общее сравнение между интерфейсом и абстрактным классом на основе их использования.

Когда нужно использовать интерфейс, а когда - абстрактный класс ?


1
Об этом много спрашивали: stackoverflow.com/questions/56867/interface-vs-base-class
mmcdole

1
В дополнение к ответам ниже, это хороший короткий список того, где вы можете предпочесть интерфейсы, а где нет. Когда использовать интерфейсы: msdn.microsoft.com/en-us/library/3b5b8ezk(v=vs.80) .aspx
Энтони

используйте абстракцию, когда вы не уверены, что будет делать класс. используйте интерфейс, если вы есть.
Угур Гюмюшан,

Мне интересно посмотреть, сколько разработчиков, которые не работают в Microsoft, определяют и используют интерфейсы в своей повседневной разработке.
user1451111

Ответы:


432

Я написал статью об этом:

Абстрактные классы и интерфейсы

Подводя итог:

Когда мы говорим об абстрактных классах, мы определяем характеристики типа объекта; указав, что такое объект .

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


114
Это было очень полезно Interfaces do not express something like "a Doberman is a type of dog and every dog can walk" but more like "this thing can walk". Спасибо
aexl

2
Похоже, ваша ссылка мертва.
Ким Алстрем Мейн Матиассен

Объяснение Алекса, приведенное ниже: различие между только описанием реализованных функций и описанием сохраненного состояния, кажется лучшим ответом на этот вопрос, потому что различия не только философские.
Дункан Малашок

1
Дункан Малашок, не совсем. Хорхе ответ лучше. Ответ Алекса фокусируется на механике, а Хорхе больше на семантике.
Назар Мерза

8
Мне нравится высказывание перед указанным вами ответом:Use abstract classes and inheritance if you can make the statement “A is a B”. Use interfaces if you can make the statement “A is capable of [doing] as”
S1r-Lanzelot

433

Абстрактный класс может иметь общее состояние или функциональность. Интерфейс - это только обещание предоставить состояние или функциональность. Хороший абстрактный класс уменьшит объем кода, который необходимо переписать, потому что его функциональность или состояние могут быть разделены. Интерфейс не имеет определенной информации для обмена


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

3
Например, абстрактный базовый класс используется для шаблона разработки метода шаблона, тогда как интерфейс используется для шаблона разработки стратегии .
Raedwald

1
Я думаю, что краткое изложение Хорхе объясняет основную причину существования их обоих, в то время как ответ Алекса - разница в результатах. Хотел бы я отметить оба ответа как правильные, но я все же предпочитаю ответ Хорхе.
Чирантан 15.12.14

И вот это пример с кодом.
Shaijut

Для меня это «хороший абстрактный класс сократит объем кода, который необходимо переписать, потому что его функциональность или состояние могут быть общими». утверждение является основой ответа.
Див Тивари

82

Лично мне почти никогда не нужно писать абстрактные классы.

В большинстве случаев я вижу, что абстрактные классы используются (неправильно), потому что автор абстрактного класса использует шаблон «Шаблонный метод».

Проблема с «Методом шаблона» заключается в том, что он почти всегда несколько повторяется - «производный» класс знает не только о «абстрактном» методе своего базового класса, который он реализует, но и о открытых методах базового класса. , хотя в большинстве случаев это не нужно называть их.

(Чрезмерно упрощенный) пример:

abstract class QuickSorter
{
    public void Sort(object[] items)
    {
        // implementation code that somewhere along the way calls:
        bool less = compare(x,y);
        // ... more implementation code
    }
    abstract bool compare(object lhs, object rhs);
}

Итак, здесь автор этого класса написал общий алгоритм и намеревается, чтобы люди использовали его, «специализируя» его, предоставляя свои собственные «крючки» - в данном случае, метод «сравнения».

Таким образом, предполагаемое использование примерно так:

class NameSorter : QuickSorter
{
    public bool compare(object lhs, object rhs)
    {
        // etc.
    }
}

Проблема в том, что вы неправильно связали воедино две концепции:

  1. Способ сравнения двух предметов (какой предмет должен идти первым)
  2. Метод сортировки элементов (например, быстрая сортировка, сортировка слиянием и т. Д.)

В приведенном выше коде теоретически автор метода «сравнение» может повторно вызывать метод «Сортировка» суперкласса ... даже на практике они никогда не захотят или не будут этого делать.

Цена, которую вы платите за эту ненужную связь, состоит в том, что трудно изменить суперкласс, и в большинстве языков OO невозможно изменить его во время выполнения.

Альтернативный метод - использовать шаблон проектирования «Стратегия»:

interface IComparator
{
    bool compare(object lhs, object rhs);
}

class QuickSorter
{
    private readonly IComparator comparator;
    public QuickSorter(IComparator comparator)
    {
        this.comparator = comparator;
    }

    public void Sort(object[] items)
    {
        // usual code but call comparator.Compare();
    }
}

class NameComparator : IComparator
{
    bool compare(object lhs, object rhs)
    {
        // same code as before;
    }
}

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

Чтобы «скрыть» тот факт, что мы реализовали «сортировку имен» с помощью класса «QuickSort» и «NameComparator», мы все равно могли бы написать метод фабрики:

ISorter CreateNameSorter()
{
    return new QuickSorter(new NameComparator());
}

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

Одна заключительная мысль: все, что мы сделали выше, это «составление» функции «NameSorting» с использованием функции «QuickSort» и функции «NameComparison» ... на функциональном языке программирования этот стиль программирования становится еще более естественным, с меньшим количеством кода.


5
То, что вы можете использовать абстрактные классы или шаблонный метод, не означает, что вам нужно избегать их. Шаблон стратегии - это другой шаблон для другой ситуации, как в этом примере, но есть много примеров, когда шаблон шаблона более подходит, чем стратегия.
Хорхе Кордова

5
Ну, по моему опыту, я никогда не сталкивался с ними (ситуации, когда метод шаблона предпочтителен) ... или редко в любом случае. И это все «абстрактно» - языковая поддержка шаблона проектирования «шаблонный метод».
Пол Холлингсворт

Хорошо, я использовал его один раз для экспертной системы, где процесс был чем-то похожим, получить 1. FillTheParameters, 2. Сделать векторное произведение между ними, 3. Для каждой пары вычислить результат, 4. Соединить результаты, где шаги 1 и 3 где делегированы и 2 и 4 реализованы в базовом классе.
Хорхе Кордова

10
Я нахожу почти любое использование абстрактных классов более сложным для понимания. Мышление в терминах блоков, которые взаимодействуют друг с другом вместо отношений наследования, легче (для меня) ... Но я также согласен с тем, что современные языки OO требуют слишком много стандартного образца ... Функциональным будет способ преодоления OO
Пол Холлингсворт

4
Пример неправильного использования довольно тривиален. Это редко сводится к такой хорошей функциональности, как сравнение. Гораздо более распространенными являются ситуации, когда есть некоторые функциональные возможности по умолчанию, которые производные классы либо заменяют, либо расширяют (и в последнем случае вполне допустимо вызывать функцию базового класса). В вашем примере нет функциональности по умолчанию, поэтому использование абстрактного класса не имеет оправдания.
SomeWittyUsername

41

Если вы смотрите на Java в качестве языка ООП,

« интерфейс не обеспечивает реализацию метода » больше не действует при запуске Java 8. Теперь Java предоставляет реализацию в интерфейсе для методов по умолчанию.

Проще говоря, я хотел бы использовать

интерфейс: для реализации контракта несколькими несвязанными объектами. Он обеспечивает возможность " HAS A ".

абстрактный класс: для реализации одинакового или разного поведения среди нескольких связанных объектов. Он устанавливает отношение " IS A ".

Oracle сайт предоставляет основные различия между interfaceи abstractклассом.

Рассмотрите возможность использования абстрактных классов, если:

  1. Вы хотите поделиться кодом между несколькими тесно связанными классами.
  2. Вы ожидаете, что классы, которые расширяют ваш абстрактный класс, имеют много общих методов или полей или требуют модификаторов доступа, отличных от public (например, protected и private).
  3. Вы хотите объявить нестатические или не финальные поля.

Рассмотрите возможность использования интерфейсов, если:

  1. Вы ожидаете, что несвязанные классы будут реализовывать ваш интерфейс. Например, многие несвязанные объекты могут реализовать Serializableинтерфейс.
  2. Вы хотите указать поведение определенного типа данных, но не беспокоитесь о том, кто реализует его поведение.
  3. Вы хотите воспользоваться множественным наследованием типа.

Пример:

Абстрактный класс ( является соотношение)

Читатель - это абстрактный класс.

BufferedReader являетсяReader

FileReader являетсяReader

FileReaderи BufferedReaderиспользуются для общей цели: чтение данных, и они связаны через Readerкласс.

Интерфейс ( ИМЕЕТ возможность)

Сериализуемый это интерфейс.

Предположим, что у вас есть два класса в вашем приложении, которые реализуют Serializableинтерфейс

Employee implements Serializable

Game implements Serializable

Здесь вы не можете установить какую-либо связь через Serializableинтерфейс между Employeeи Game, которые предназначены для разных целей. Оба способны сериализировать состояние, и сравнение на этом заканчивается.

Посмотрите на эти сообщения:

Как мне объяснить разницу между интерфейсом и абстрактным классом?


40

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

Абстрактные классы позволяют создавать чертежи и дополнительно КОНСТРУКТИВНО (реализовывать) свойства и методы, которые должны быть доступны ВСЕМ его потомкам.

Интерфейс, с другой стороны, позволяет вам только объявить, что вы хотите, чтобы свойства и / или методы с заданным именем существовали во всех классах, которые его реализуют, но не указывает, как вы должны это реализовать. Кроме того, класс может реализовывать МНОГО интерфейсов, но может расширять только ОДИН абстрактный класс. Интерфейс - это скорее высокоуровневый архитектурный инструмент (который становится понятнее, если вы начнете понимать шаблоны проектирования) - абстрактная работа в обоих лагерях позволяет выполнять некоторые грязные задачи.

Зачем использовать один над другим? Первое допускает более конкретное определение потомков - второе допускает больший полиморфизм . Этот последний пункт важен для конечного пользователя / кодера, который может использовать эту информацию для реализации AP I (интерфейса) в различных комбинациях / формах, чтобы удовлетворить их потребности.

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


основываться на этом: объект, который реализует интерфейс, принимает его ТИП. Это очень важно. Таким образом, вы можете передавать различные варианты интерфейса в класс, но обращаться к ним (и их методам) С ИМЯ ТИПА ИНТЕРФЕЙСА. Таким образом, вы устраняете необходимость в переключателе или цикле if / else. Попробуйте этот урок по теме - он демонстрирует использование интерфейса через шаблон стратегии. phpfreaks.com/tutorial/design-patterns---strategy-and-bridge/…
sunwukung

Я полностью согласен с вашим моментом лампочки: «API (nterface) в различных комбинациях / формах, чтобы удовлетворить их потребности»! Очень, очень хорошее замечание.
Тревор Бойд Смит

39

Мои два цента:

Интерфейс в основном определяет контракт, которого должен придерживаться любой реализующий класс (реализовать элементы интерфейса). Он не содержит никакого кода.

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

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

Пример (очень зачаточном один!): Рассмотрим базовый класс с именем клиента , который имеет абстрактные методы , как CalculatePayment(), CalculateRewardPoints()и некоторые не абстрактные методы , как GetName(), SavePaymentDetails().

Специализированные классы , как RegularCustomer и GoldCustomerнаследует от Customerбазового класса и реализовать свои собственные CalculatePayment()и CalculateRewardPoints()логику метода, но повторно использовать GetName()и SavePaymentDetails()методы.

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

Абстрактный класс со всеми абстрактными членами будет похож на интерфейс.


1
+1 за "Вы можете добавить больше функциональных возможностей к абстрактному классу (т.е. не абстрактным методам), не затрагивая дочерние классы, которые использовали более старую версию. Принимая во внимание, что добавление методов к интерфейсу затронет все классы, реализующие его, так как им теперь нужно будет реализовать недавно добавленные члены интерфейса. "
Див Тивари

интерфейсы могут иметь методы «по умолчанию», так что отсутствие метода impl в интерфейсах - неправильная идея. Отношения «родитель-ребенок» IS-A - вот ключ. Кроме того, «Общие атрибуты» против «Общие свойства». напр. собака iS-A Animal. Но собака также может "гулять"
ha9u63ar

30

Когда делать то, что очень просто, если у вас в голове есть ясная концепция.

Абстрактные классы могут быть получены, тогда как интерфейсы могут быть реализованы. Есть некоторая разница между ними. Когда вы наследуете абстрактный класс, отношения между производным классом и базовым классом являются отношениями «это». Например, Собака - это Животное, Овца - это Животное, что означает, что производный класс наследует некоторые свойства от базового класса.

Принимая во внимание, что для реализации интерфейсов, отношение «может быть». например, собака может быть шпионской собакой. Собака может быть цирковой собакой. Собака может быть гоночной собакой. Это означает, что вы реализуете определенные методы для приобретения чего-либо.

Я надеюсь, что я ясно.


11

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

2. Если вы создаете что-то для объектов, тесно связанных в иерархии, используйте абстрактный класс.


10

Я написал статью о том, когда использовать абстрактный класс, а когда использовать интерфейс. Между ними существует гораздо больше различий, кроме "один IS-A ... и один CAN-DO ...". Для меня это консервированные ответы. Я упоминаю несколько причин, когда использовать любой из них. Надеюсь, поможет.

http://codeofdoom.com/wordpress/2009/02/12/learn-this-when-to-use-an-abstract-class-and-an-interface/


7

Я думаю, что самый краткий способ выразить это следующим образом:

Общие свойства => абстрактный класс.
Общая функциональность => интерфейс.

И, если выразиться менее кратко ...

Пример абстрактного класса:

public abstract class BaseAnimal
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }
}

public class Dog : BaseAnimal
{
    public Dog() : base(4) { }
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }
}

Поскольку у животных есть общее свойство - в данном случае количество ног - имеет смысл создать абстрактный класс, содержащий это общее свойство. Это также позволяет нам писать общий код, который работает с этим свойством. Например:

public static int CountAllLegs(List<BaseAnimal> animals)
{
    int legCount = 0;
    foreach (BaseAnimal animal in animals)
    {
        legCount += animal.NumberOfLegs;
    }
    return legCount;
}

Пример интерфейса:

public interface IMakeSound
{
    void MakeSound();
}

public class Car : IMakeSound
{
    public void MakeSound() => Console.WriteLine("Vroom!");
}

public class Vuvuzela : IMakeSound
{
    public void MakeSound() => Console.WriteLine("VZZZZZZZZZZZZZ!");        
}

Обратите внимание, что Vuvuzelas и Cars - это совершенно разные вещи, но они имеют общую функциональность: создание звука. Таким образом, интерфейс имеет смысл здесь. Кроме того, это позволит программистам группировать вещи, которые издают звуки, в едином интерфейсе - IMakeSoundв данном случае. С этим дизайном вы могли бы написать следующий код:

List<IMakeSound> soundMakers = new List<ImakeSound>();
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Vuvuzela());

foreach (IMakeSound soundMaker in soundMakers)
{
    soundMaker.MakeSound();
}

Можете ли вы сказать, что это будет выводить?

Наконец, вы можете объединить два.

Комбинированный пример:

public interface IMakeSound
{
    void MakeSound();
}

public abstract class BaseAnimal : IMakeSound
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }

    public abstract void MakeSound();
}

public class Cat : BaseAnimal
{
    public Cat() : base(4) { }

    public override void MakeSound() => Console.WriteLine("Meow!");
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }

    public override void MakeSound() => Console.WriteLine("Hello, world!");
}

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

Еще один момент, помните, как в примере с абстрактным классом мы могли работать с общими свойствами различных объектов, а в примере интерфейса мы могли вызывать общую функциональность различных объектов? В этом последнем примере мы могли бы сделать оба.


7

Когда предпочитать абстрактный класс интерфейсу?

  1. Если планируется обновление базового класса в течение всей жизни программы / проекта, лучше всего разрешить, чтобы базовый класс был абстрактным классом.
  2. Если кто-то пытается создать основу для объектов, тесно связанных в иерархии, очень полезно использовать абстрактный класс

Когда предпочитать интерфейс над абстрактным классом?

  1. Если кто-то не имеет дело с массивным иерархическим типом фреймворка, интерфейс будет отличным выбором
  2. Поскольку множественное наследование не поддерживается с абстрактными классами (проблема с бриллиантами), интерфейсы могут сэкономить время

Что заставило вас думать, что почти десятилетний вопрос нуждается в 22-м ответе?
Джоншарп

3
Тот же тип мышления, который заставил меня искать простой ответ на вопрос.
Сатья

1
FWIW, я действительно люблю этот ответ.
Брент Риттенхаус

6

Классы могут наследовать только от одного базового класса, поэтому, если вы хотите использовать абстрактные классы для обеспечения полиморфизма для группы классов, все они должны наследовать от этого класса. Абстрактные классы также могут предоставлять члены, которые уже были реализованы. Следовательно, вы можете обеспечить определенное количество идентичных функциональных возможностей с помощью абстрактного класса, но не можете с помощью интерфейса.

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

  • Если вы планируете создать несколько версий вашего компонента, создайте абстрактный класс. Абстрактные классы предоставляют простой и легкий способ создания версий ваших компонентов. При обновлении базового класса все наследующие классы автоматически обновляются с изменением. Интерфейсы, с другой стороны, не могут быть изменены после создания таким образом. Если требуется новая версия интерфейса, вы должны создать совершенно новый интерфейс.
  • Если создаваемая вами функциональность будет полезна для широкого круга разнородных объектов, используйте интерфейс. Абстрактные классы следует использовать в первую очередь для объектов, которые тесно связаны, тогда как интерфейсы лучше всего подходят для предоставления общих функций несвязанным классам.
  • Если вы разрабатываете небольшие, лаконичные кусочки функциональности, используйте интерфейсы. Если вы разрабатываете большие функциональные блоки, используйте абстрактный класс.
  • Если вы хотите обеспечить общую, реализованную функциональность среди всех реализаций вашего компонента, используйте абстрактный класс. Абстрактные классы позволяют вам частично реализовать ваш класс, тогда как интерфейсы не содержат реализации для каких-либо членов.

Скопировано с:
http://msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx


В UML нет ничего, что исключало бы наследование нескольких классов. Множественное наследование определяется языком программирования, а не UML. Например, множественное наследование классов не разрешено в Java и C #, но разрешено в C ++.
BobRodes

@BobRodes: Есть ряд функций, которые объектно-ориентированные платформы могут предоставлять в различных комбинациях, но не во всех комбинациях. Обобщенное множественное наследование исключает некоторые другие полезные комбинации функций, включая возможность приведения ссылки непосредственно к любому родительскому типу фактического экземпляра или любого поддерживаемого таким образом типа интерфейса, а также возможность независимо компилировать базовые типы и производные типы и объединять их во время выполнения.
суперкат

@supercat Yours - хорошее объяснение некоторых проблем, возникающих в результате использования множественного наследования. Тем не менее, в UML нет ничего, что препятствовало бы множественному наследованию классов в диаграмме. Я отвечал на вышеупомянутое «Классы могут наследовать только от одного базового класса ...», что не совсем так.
BobRodes

@BobRodes: вопрос был помечен Java. Java включает в себя указанные функции и, таким образом, ограничивается формами множественного наследования, которые не могут привести к «смертельному бриллианту» (хотя фактически способ, которым они реализовали реализации интерфейса по умолчанию, делает возможным смертельный бриллиант).
суперкат

@supercat О, хорошо. Я обычно не смотрю на теги java, поэтому в то время, когда я писал, я, по крайней мере, думал, что комментирую ответ UML. В любом случае я согласен с вашим комментарием.
BobRodes

3

Рассмотрите возможность использования абстрактных классов, если любое из этих утверждений применимо к вашей ситуации:

  1. Вы хотите поделиться кодом между несколькими тесно связанными классами.
  2. Вы ожидаете, что классы, которые расширяют ваш абстрактный класс, имеют много общих методов или полей или требуют модификаторов доступа, кроме public (например, protected и private).
  3. Вы хотите объявить нестатические или не финальные поля. Это позволяет вам определять методы, которые могут получать доступ и изменять состояние объекта, к которому они принадлежат.

Рассмотрите возможность использования интерфейсов, если любое из этих утверждений применимо к вашей ситуации:

  1. Вы ожидаете, что несвязанные классы будут реализовывать ваш интерфейс. Например, интерфейсы Comparable и Cloneable реализованы многими несвязанными классами.
  2. Вы хотите указать поведение определенного типа данных, но не беспокоитесь о том, кто реализует его поведение.
  3. Вы хотите воспользоваться несколькими наследованиями.

Источник


2

Ответы различаются в зависимости от языка. Например, в Java класс может реализовывать (наследовать) несколько интерфейсов, но наследовать только от одного абстрактного класса. Таким образом, интерфейсы дают вам больше гибкости. Но это не так в C ++.


2

Для меня я бы пошел с интерфейсами во многих случаях. Но я предпочитаю абстрактные классы в некоторых случаях.

Классы в ОО вообще относятся к реализации. Я использую абстрактные классы, когда хочу навязать некоторые детали реализации дочерним элементам, иначе я использую интерфейсы.

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


1

Используйте абстрактный класс, если вы хотите предоставить некоторые базовые реализации.


1
Спасибо Себастьян. Но что, если мне не нужна базовая реализация? Разве абстрактный класс и интерфейс не будут одинаковыми, если это единственное различие между ними? Почему есть разница?
Chirantan

1
Потому что некоторые языки не имеют интерфейсов - C ++.
jmucchiello

1

в Java вы можете наследовать от одного (абстрактного) класса, чтобы «обеспечить» функциональность, и вы можете реализовать много интерфейсов, чтобы «обеспечить» функциональность


Подсказка: если вы хотите наследовать от абстрактного класса и интерфейса, убедитесь, что абстрактный класс реализует интерфейс
Andreas Niedermair

1

Чисто на основе наследования вы будете использовать реферат, в котором вы определяете явно наследуемые, абстрактные отношения (например, animal-> cat) и / или требуете наследования виртуальных или непубличных свойств, особенно общего состояния (которое интерфейсы не могут поддерживать). ).

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


1

Одно интересное место, где интерфейсы работают лучше, чем абстрактные классы, это когда вам нужно добавить дополнительную функциональность в группу (связанных или не связанных) объектов. Если вы не можете дать им базовый абстрактный класс (например, они имеют sealedили уже имеют родителя), вы можете вместо этого дать им фиктивный (пустой) интерфейс, а затем просто написать методы расширения для этого интерфейса.


0

Это может быть очень сложный вызов ...

Один указатель, который я могу дать: объект может реализовать много интерфейсов, в то время как объект может наследовать только один базовый класс (в современном языке OO, таком как c #, я знаю, что C ++ имеет множественное наследование - но разве это не осуждается?)


Множественное наследование позволяет реализовать Mixin без всяких сомнений, хорошо написанные Mixin - это бриз, с которым легко работать, но его очень сложно найти и трудно написать, не упуская где-то. Mixin's довольно круты в целом, хотя IMO.
Мартин Ларман

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

Единственное, что я пытался сделать, - это то, что способы Mixin в языках с Single Inheritence тоже возможны (C #, PHP, javascript), но через хакерское поведение или хитрый синтаксис. Мне нравятся Mixin's, когда они работают, но я все еще не решаюсь по поводу множественного наследования или нет.
Мартин Ларман

Этот ответ является скорее синтаксической разницей, чем конструктивной разницей. Я думаю, что он просит о разнице в дизайне
Pramod Setlur

0

Абстрактный класс может иметь реализации.

Интерфейс не имеет реализаций, он просто определяет вид контракта.

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


Когда вы говорите «своего рода контракт», вы имеете в виду, как в веб-сервисах?
Chirantan

Технически говоря, веб-сервисы не работают с интерфейсами. Под контрактом я подразумеваю, что пользователь объекта знает, какие методы присутствуют в этом объекте. Например, интерфейс IMouse будет иметь метод Move и левую и правую кнопку мыши.
Джерри Шенк

-1

Основное правило большого пальца: для "Существительных" используйте абстрактный класс, а для "Глаголов" используйте интерфейс

Например: carэто абстрактный класс, и driveмы можем сделать его интерфейсом.


5
Это не имеет смысла, мы также можем поместить функциональность driveв автомобиль - это абстрактный класс.
Арслан Али
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.