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


427

Це може бути загальне питання про ООП. Я хотів зробити загальне порівняння між інтерфейсом та абстрактним класом на основі їх використання.

Коли хотілося б використовувати інтерфейс і коли потрібно використовувати абстрактний клас ?


1
Це було запропоновано багато: stackoverflow.com/questions/56867/interface-vs-base-class
mmcdole

1
У доповненнях до відповідей нижче це хороший короткий список того, де ви хочете віддати перевагу інтерфейсам, а де ви не можете: Коли використовувати інтерфейси: msdn.microsoft.com/en-us/library/3b5b8ezk(v=vs.80) .aspx
Ентоні

використовуйте реферат, коли ви не впевнені, що збираєтеся робити клас. використовуйте інтерфейс, якщо ви є.
Uğur Gümüşhan

Мені цікаво побачити, як багато розробників, які не працюють в Microsoft, визначають та використовують інтерфейси у своїй щоденній розробці.
user1451111

Відповіді:


431

Я написав статтю про це:

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

Підсумовуючи:

Коли ми говоримо про абстрактні класи, ми визначаємо характеристики типу об'єкта; уточнення, що таке об’єкт .

Коли ми говоримо про інтерфейс і визначаємо можливості, які ми обіцяємо надати, ми говоримо про встановлення договору про те, що може зробити об'єкт.


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
Здається, що ваше посилання мертве.
Kim Ahlstrøm Meyn Mathiassen

Пояснення Алекса нижче: повтор: різниця між лише описуючими функціями, реалізованими, а також описом стану, що зберігається, здається кращою відповіддю на це питання, оскільки відмінності не є лише філософськими.
Дункан Малашок

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
Я думаю, що підсумок Хорхе пояснює першочергове, хоча позаду існування для обох, тоді як відповідь Алекса - різниця в результатах. Я б хотів, щоб я міг позначити обидві як правильні відповіді, але все ж віддаю перевагу відповідь Хорхе.
Чирантан

І ось це приклад з кодом.
shaijut

Для мене цей "хороший абстрактний клас зменшить кількість коду, який потрібно переписати, оскільки його функціональність або стан можна поділити". твердження - це серцевина відповіді.
Div Tiwari

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" та функцію "NameCompparement" ... у функціональній мові програмування цей стиль програмування стає ще більш природним, з меншим кодом.


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

5
Ну, на моєму досвіді я ніколи не натрапляю на них (ситуації, коли шаблонний метод є кращим) ... або рідко все одно. І це все "абстрактно" - мовна підтримка шаблону дизайну "метод шаблону".
Пол Холлінгсворт,

Добре, я використовував це один раз для експертної системи, де процес був чимось подібний, отримайте 1. FillTheParameters, 2. Зробіть векторний продукт між ними, 3. Для кожного результату обчислення пари, 4. Приєднайтеся до результатів, де кроки 1 і 3 де делеговані та 2 та 4 реалізовані в базовому класі.
Хорхе Кордова

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

4
Приклад неправильного використання досить тривіальний. Він рідко зводиться до такого приємного позбавленого функціоналу, як порівняння. Набагато частіше зустрічаються ситуації, коли існує деяка функціональність за замовчуванням, яку похідні класи або замінюють, або розширюють (і в останньому випадку цілком справедливо називати функцію базового класу). У вашому прикладі відсутня функціональність за замовчуванням, тому використання абстрактного класу не має виправдання.
SomeWittyUsername

41

Якщо ви розглядаєте java як мову OOP,

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

Простіше кажучи, я хотів би використати

інтерфейс: для реалізації договору декількома непов'язаними об'єктами. Він забезпечує можливість " HAS A ".

абстрактний клас: реалізувати однакову або різну поведінку серед декількох пов'язаних об'єктів. Він встановлює відношення " IS A ".

Веб-сайт Oracle пропонує ключові відмінності між класом interfaceта abstractкласом.

Подумайте про використання абстрактних класів, якщо:

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

Подумайте про використання інтерфейсів, якщо:

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

Приклад:

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

Читач - абстрактний клас.

BufferedReader - цеReader

FileReader - цеReader

FileReaderі BufferedReaderвикористовуються для загальної мети: Читання даних, і вони пов'язані через Readerклас.

Інтерфейс (можливість HAS A )

Serializable - це інтерфейс.

Припустимо, що у вашій програмі є два класи, які реалізують Serializableінтерфейс

Employee implements Serializable

Game implements Serializable

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

Подивіться на ці пости:

Як я повинен пояснити різницю між класом інтерфейсу та абстрактним?


40

Гаразд, щойно "пограбував" цим самим - ось це з точки зору мирян (не соромтеся виправити мене, якщо я помиляюся) - я знаю, що ця тема є оооооооооооооохоляді, але хтось інший може натрапити на неї одного дня ...

Абстрактні класи дозволяють створити креслення і дозволяють додатково ПОБУДОВАТИ (реалізувати) властивості та методи, якими ви хочете ВСІХ своїх нащадків.

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

Навіщо використовувати один над іншим? Перший дозволяє більш конкретно визначити нащадків - другий дозволяє посилити поліморфізм . Цей останній момент важливий для кінцевого користувача / кодера, який може використовувати цю інформацію для реалізації AP I (nterface) у різноманітних комбінаціях / формах відповідно до їх потреб.

Я думаю, що це був момент "лампочки" для мене - подумай про інтерфейси менше з точки зору автора і більше від будь-якого кодера, який з’явиться пізніше в ланцюжку, який додає реалізацію до проекту чи розширює API.


на основі цього: Об'єкт, що реалізує інтерфейс, бере на себе TYPE. Це є вирішальним. Отже, ви можете передавати різні варіанти інтерфейсу класу, але зверніться до них (та їх методів) З ТИПУ ІМЕ ІНТЕРФЕЙСУ. Таким чином, ви усуваєте необхідність перемикання або циклу if / else. Спробуйте цей підручник з цього питання - він демонструє використання інтерфейсу через шаблон стратегії. phpfreaks.com/tutorial/design-patterns---strategy-and-bridge/…
sunwukung

Я повністю погоджуюся з вашим моментом лампочки: "API (інтерфейс) у різних комбінаціях / формах, щоб відповідати їх потребам"! Дуже хороший момент.
Тревор Бойд Сміт

39

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

Інтерфейс в основному визначає контракт, якого повинен дотримуватися будь-який клас реалізації (реалізувати учасників інтерфейсу). Він не містить жодного коду.

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

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

Приклад (дуже зародковому один!): Розглянемо базовий клас з ім'ям клієнта , який має абстрактні методи , як CalculatePayment(), CalculateRewardPoints()і деякі не абстрактні методи , як GetName(), SavePaymentDetails().

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

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

Абстрактний клас із усіма абстрактними членами буде подібний до інтерфейсу.


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

інтерфейси можуть мати методи «за замовчуванням», тому відсутність імпульсу методу в інтерфейсах - неправильна ідея. ІС-A стосунки "батько-дитина" є ключовим тут. Також "Спільні атрибути" проти "Спільні властивості". наприклад, тварина iS-A собаки. Але собака також може «
гуляти

30

Коли робити те, що є дуже простою справою, якщо у вас в думці є чітка концепція.

Абстрактні класи можна отримати, тоді як інтерфейси можуть бути реалізовані. Існує деяка різниця між ними. Коли ви отримуєте абстрактний клас, відношення між похідним класом і базовим класом є "є" відношенням. наприклад, собака - тварина, вівця - тварина, що означає, що похідний клас успадковує деякі властивості від базового класу.

Тоді як для реалізації інтерфейсів взаємозв'язок "може бути". наприклад, собака може бути собакою-шпигуном. Собака може бути цирковою собакою. Собака може бути расовою собакою. Що означає, що ви реалізуєте певні методи, щоб щось придбати.

Я сподіваюся, що я зрозумів.


11

1. Якщо ви створюєте щось, що забезпечує загальну функціональність для непов'язаних класів, використовуйте інтерфейс.

2.Якщо ви створюєте щось для об'єктів, тісно пов'язаних в ієрархії, використовуйте абстрактний клас.


10

Я написав статтю про те, коли використовувати абстрактний клас та коли використовувати інтерфейс. Різниця між ними є набагато більше, ніж "один IS-A ... і один CAN-DO ...". Мені це відповіді в консервах. Я згадую кілька причин, коли використовувати будь-яку з них. Сподіваюся, це допомагає.

http://codeofdoom.com/wordpress/2009/02/12/learn-this-when-to-use-an-abrief-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!");        
}

Зауважте тут, що Вувузелас і Автомобілі - це абсолютно різні речі, але вони мають спільну функціональність: виголошуючи звук. Таким чином, тут є сенс інтерфейсу. Далі це дозволить програмістам згрупувати речі, які видають звуки разом під загальним інтерфейсом - 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-ї відповіді?
jonrsharpe

3
Той самий тип мислення, який змусив мене знайти просту відповідь на питання.
Сатья

1
FWIW, я дуже люблю цю відповідь.
Brent Rittenhouse

6

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

Ось кілька рекомендацій, які допоможуть вам вирішити, чи використовувати інтерфейс чи абстрактний клас для надання поліморфізму для своїх компонентів.

  • Якщо ви передбачаєте створення декількох версій свого компонента, створіть абстрактний клас. Абстрактні заняття пропонують простий і простий спосіб версії своїх компонентів. Оновленням базового класу всі спадкові класи автоматично оновлюються зі зміною. Інтерфейси, з іншого боку, неможливо змінити, коли вони створені таким чином. Якщо потрібна нова версія інтерфейсу, потрібно створити абсолютно новий інтерфейс.
  • Якщо створена вами функціональність буде корисною для широкого спектру різних об'єктів, використовуйте інтерфейс. Абстрактні класи слід використовувати насамперед для тісно пов'язаних між собою об'єктів, тоді як інтерфейси найкраще підходять для надання загальної функціональності непов'язаним класам.
  • Якщо ви розробляєте невеликі, стислі біти функціональності, використовуйте інтерфейси. Якщо ви проектуєте великі функціональні одиниці, використовуйте абстрактний клас.
  • Якщо ви хочете надати загальну реалізовану функціональність серед усіх реалізацій вашого компонента, використовуйте абстрактний клас. Абстрактні класи дозволяють частково реалізувати свій клас, тоді як інтерфейси не містять жодної реалізації.

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


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

@BobRodes: Є ряд функцій, які об'єктно-орієнтовані рамки можуть надавати в різних комбінаціях, але не у всіх комбінаціях. Узагальнене багаторазове успадкування виключає деякі інші корисні комбінації функцій, включаючи можливість передавати посилання безпосередньо на будь-який батьківський тип фактичного екземпляра або будь-який підтримуваний тим самим тип інтерфейсу та можливість самостійно компілювати базові типи та похідні типи та приєднувати їх під час виконання.
supercat

@supercat Ваше - це хороше пояснення деяких проблем, які виникають внаслідок використання багаторазового успадкування. Тим не менш, в UML немає нічого, що виключає успадкування кількох класів на діаграмі. Я відповідав на вищезазначене "Класи можуть успадковувати лише один базовий клас ...", що не зовсім так.
BobRodes

@BobRodes: Питання було позначено Java. Java включає вказані функції, і, таким чином, обмежується формами багаторазового успадкування, які не можуть створити "смертоносний алмаз" (хоча насправді те, як вони реалізували реалізацію інтерфейсу за замовчуванням, робить можливим смертоносний алмаз).
supercat

@supercat О, добре. Я зазвичай не дивлюся на теги java, тому під час написання, що я, принаймні, думав, що коментую відповідь UML. У будь-якому випадку я згоден з вашим коментарем.
BobRodes

3

Подумайте про використання абстрактних класів, якщо якесь із цих тверджень стосується вашої ситуації:

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

Подумайте про використання інтерфейсів, якщо якесь із цих тверджень стосується вашої ситуації:

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

Джерело


2

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


2

Для мене я б ходив із інтерфейсами у багатьох випадках. Але я віддаю перевагу абстрактним заняттям у деяких випадках.

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

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


1

Використовуйте абстрактний клас, якщо ви хочете надати деякі основні реалізації.


1
Спасибі Себастьян. Але що робити, якщо мені не потрібно мати базову реалізацію? Не хочете, щоб абстрактний клас та інтерфейс були однаковими, якщо це єдина різниця між ними? Чому є різниця?
Чирантан

1
Оскільки деякі мови не мають інтерфейсів - C ++.
jmucchiello

1

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


lil 'натяк: якщо ви хочете успадкувати абстрактний клас та інтерфейс, будьте впевнені, що абстрактний клас реалізує інтерфейс
Andreas Niedermair

1

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

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


1

Одне цікаве місце, де інтерфейси працюють краще, ніж абстрактні класи, - коли вам потрібно додати додаткову функціональність до групи (пов'язаних або неспоріднених) об’єктів. Якщо ви не можете дати їм базовий абстрактний клас (наприклад, у них є sealedабо вже є батьківський), ви можете надати їм фіктивний (порожній) інтерфейс, а потім просто написати методи розширення для цього інтерфейсу.


0

Це може бути дуже важким закликом зробити ...

Один вказівник, який я можу дати: Об'єкт може реалізовувати багато інтерфейсів, тоді як об'єкт може успадковувати лише один базовий клас (у сучасній мові OO, як c #, я знаю, що C ++ має декілька успадкованих - але це не нахмурено?)


Багатократне успадкування дозволяє Міксіну реалізуватись, здавалося б, добре написані Мікіна - це легкий досвід роботи, але дуже важко підійти і важко писати, не провалюючись кудись. У цілому Mixin є досить крутим, хоча ІМО.
Martijn Laarman

Насправді я цього не зробив, багатократне успадкування - це справді впевнений дебат між нами вундеркіндами, я не бачу абсолютно жодних причин спростовувати. Насправді я підтримав вашу відповідь.
Martijn Laarman

Єдиний пункт, який я намагався зробити, - це те, що способи змішування в мовах з єдиною спадковою можливістю також є (C #, PHP, javascript), але через хакейську поведінку чи синтаксис липкого характеру. Я люблю Мікіна, коли вони працюють, але я все ще нерішучий, наскільки я отримую багато разів успадковування чи ні.
Martijn Laarman

Ця відповідь - це більше синтаксична різниця, ніж різниця у дизайні. Я думаю, що він просить різниці в дизайні
Pramod Setlur

0

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

Інтерфейс не має реалізацій, він просто визначає вид контракту.

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


Коли ви говорите "своєрідний контракт", ви маєте на увазі, як у веб-сервісах?
Чирантан

Технічно кажучи, веб-сервіси не працюють з інтерфейсами. Під контрактом я маю на увазі, що користувач об'єкта знає, які методи існують на цьому об’єкті. Наприклад, інтерфейс IMouse матиме метод Move та ліву та праву кнопку миші.
Геррі Шенк

-1

Основне правило великого пальця: Для "Іменників" використовуйте клас "Анотація", а для "Дієслова" - інтерфейс

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


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