Вопрос: Интерфейс против абстрактного класса (общий OO)


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

По моему опыту, я думаю, что верно следующее. Если мне не хватает важного момента, пожалуйста, дайте мне знать.

Интерфейс:

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

Аннотация Класс:

Подкласс должен выполнять только абстрактные методы. Класс Abstract может иметь нормальные методы с реализациями. Абстрактный класс также может иметь переменные класса рядом с событиями, делегатами, свойствами и методами. Класс может реализовать только один абстрактный класс только из-за отсутствия множественного наследования в C #.

  1. После всего этого интервьюер придумал вопрос «Что делать, если у вас был абстрактный класс с абстрактными методами? Как это будет отличаться от интерфейса?» Я не знал ответа, но я думаю, что это наследство, как указано выше, правильно?

  2. Другой интервьюер спросил меня, что, если у вас есть переменная Public внутри интерфейса, как бы это отличалось от абстрактного класса? Я настаивал, что вы не можете иметь переменную public внутри интерфейса. Я не знал, что он хотел услышать, но он тоже не был удовлетворен.

Смотрите также :


1187


источник


Ответы:


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

В .NET (аналогично Java):

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

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

В самом деле, есть идиома C ++, называемая не виртуальным интерфейсом (NVI), где общедоступные методы - это не виртуальные методы, которые «thunk» для частных виртуальных методов:


626



Как насчет аналогий: когда я был в ВВС, я пошел на пилотную подготовку и стал пилотом ВВС США (ВВС США). В тот момент я не был способен летать ни на что, и должен был учиться на самолете. Как только я получил квалификацию, я был пилотом (класс Abstract) и пилотом C-141 (конкретный класс). По одному из моих заданий мне была предоставлена ​​дополнительная пошлина: сотрудник службы безопасности. Теперь я все еще пилот и пилот C-141, но я также выполнял обязанности сотрудника по вопросам безопасности (я, так сказать, реализовал ISafetyOfficer). Пилот не должен был быть офицером безопасности, другие люди могли бы это сделать.

Все пилоты ВВС США должны соблюдать некоторые правила ВВС, и все пилоты C-141 (или F-16 или T-38) являются «пилотами ВВС США». Любой может быть офицером безопасности. Итак, подведем итог:

  • Пилот: абстрактный класс
  • C-141 Pilot: конкретный класс
  • Сотрудник ISafety: интерфейс

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


751



Я думаю, что ответ, который они ищут, является фундаментальной или OPPS-философской разницей.

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

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

Напр. Автомобиль и грузовик разделяют множество основных свойств и поведения автомобильного абстрактного класса, но они также разделяют некоторое периферийное поведение, такое как генерация выхлопа, который разделяют даже не автомобильные классы, такие как Drillers или PowerGenerators, и не обязательно определяет автомобиль или грузовик , поэтому Car, Truck, Driller и PowerGenerator могут использовать один и тот же интерфейс IExhaust.


193



Краткие: абстрактные классы используются для моделирование иерархию классов аналогичных классов (например, Animal может быть абстрактным классом, а Human, Lion, Tiger могут быть конкретными производными классами)

А ТАКЖЕ

Интерфейс используется для связь между двумя аналогичными / не похожими классами, которые не заботятся о типе реализующего интерфейс интерфейса (например, Height может быть интерфейсом, и он может быть реализован Human, Building, Tree. Не имеет значения, можете ли вы поесть, вы можете искупать вас может умереть или что-то еще .. важно только то, что вам нужно иметь высоту (реализация в вашем классе)).


160



Есть еще пара отличий -

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

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

Абстрактные базовые классы могут быть изменены в версии v2 + без нарушения API. Изменения в интерфейсах нарушают изменения.

[C # /. NET Specific] Интерфейсы, в отличие от абстрактных базовых классов, могут применяться к типам значений (structs). Структуры не могут наследоваться от абстрактных базовых классов. Это позволяет применять поведенческие контракты / правила использования для типов значений.


74



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

public class Vehicle {
    private Driver driver;
    private Seat[] seatArray; //In java and most of the Object Oriented Programming(OOP) languages, square brackets are used to denote arrays(Collections).
    //You can define as many properties as you want here ...
}

Теперь велосипед ...

public class Bicycle extends Vehicle {
    //You define properties which are unique to bicycles here ...
    private Pedal pedal;
}

И автомобиль ...

public class Car extends Vehicle {
    private Engine engine;
    private Door[] doors;
}

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

Абстрактные классы

Абстрактные классы неполный объекты. Чтобы понять это дальше, давайте рассмотрим аналогию с автомобилем еще раз.
Автомобиль можно управлять. Правильно? Но разные транспортные средства управляются по-разному ... Например, вы не можете управлять автомобилем так же, как вы едете на велосипеде.
Итак, как представить функцию привода транспортного средства? Труднее проверить, что это за автомобиль, и управлять им своей собственной функцией; вам придется менять класс драйвера снова и снова при добавлении нового типа транспортного средства.
Здесь идет роль абстрактных классов и методов. Вы можете определить метод диска как абстрактный, чтобы сказать, что каждый наследующий ребенок должен реализовать эту функцию.
Поэтому, если вы измените класс автомобиля ...

//......Code of Vehicle Class
abstract public void drive();
//.....Code continues

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

Интерфейсы Интерфейсы полностью неполны. У них нет никаких свойств. Они просто указывают, что наследующие дети способны что-то сделать ...
Предположим, у вас с вами разные типы мобильных телефонов. Каждый из них имеет разные способы выполнения различных функций; Пример: вызов человека. Производитель телефона указывает, как это сделать. Здесь мобильные телефоны могут набирать номер, т. Е. Набирать номер. Представим это как интерфейс.

public interface Dialable {
    public void dial(Number n);
}

Здесь создатель Dialable определяет, как набирать номер. Вам просто нужно дать ему номер для набора.

// Makers define how exactly dialable work inside.

Dialable PHONE1 = new Dialable() {
    public void dial(Number n) {
        //Do the phone1's own way to dial a number
    }
}

Dialable PHONE2 = new Dialable() {
    public void dial(Number n) {
        //Do the phone2's own way to dial a number
    }
}


//Suppose there is a function written by someone else, which expects a Dialable
......
public static void main(String[] args) {
    Dialable myDialable = SomeLibrary.PHONE1;
    SomeOtherLibrary.doSomethingUsingADialable(myDialable);
}
.....

Таким образом, используя интерфейсы вместо абстрактных классов, писателю функции, которая использует Dialable, не нужно беспокоиться о ее свойствах. Пример: есть ли сенсорный экран или панель набора номера, это стационарный стационарный телефон или мобильный телефон. Вам просто нужно знать, является ли он доступным; он наследует (или реализует) интерфейс Dialable.

И что еще более важно , если когда-нибудь вы переключите Dialable с другим

......
public static void main(String[] args) {
    Dialable myDialable = SomeLibrary.PHONE2; // <-- changed from PHONE1 to PHONE2
    SomeOtherLibrary.doSomethingUsingADialable(myDialable);
}
.....

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

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

Больше информации Абстрактные классы vs Интерфейсы


61



Если вы считаете javaкак язык ООП для ответа на этот вопрос, выпуск Java 8 приводит к тому, что некоторые из приведенных выше ответов являются устаревшими. Теперь интерфейс java может иметь методы по умолчанию с конкретной реализацией.

оракул Веб-сайт обеспечивает ключевые различия между interfaceа также abstractкласс.

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

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

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

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

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

интерфейс: Для реализации контракта несколькими несвязанными объектами

абстрактный класс: Чтобы реализовать одно и то же или другое поведение между несколькими связанными объектами

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


31



The interviewers are barking up an odd tree. For languages like C# and Java, there is a difference, but in other languages like C++ there is not. OO theory doesn't differentiate the two, merely the syntax of language.

An abstract class is a class with both implementation and interface (pure virtual methods) that will be inherited. Interfaces generally do not have any implementation but only pure virtual functions.

In C# or Java an abstract class without any implementation differs from an interface only in the syntax used to inherit from it and the fact you can only inherit from one.


30



By implementing interfaces you are achieving composition ("has-a" relationships) instead of inheritance ("is-a" relationships). That is an important principle to remember when it comes to things like design patterns where you need to use interfaces to achieve a composition of behaviors instead of an inheritance.


29