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

15

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

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

Вот два класса, которые я создал:

class Ad {
    $title;
    $description
    $price;

    function get_data($website){  }

    function validate_price(){  }
 }


class calendar_event {
    $title;
    $description

    $start_date;

    function get_data($website){ //guts }

    function validate_dates(){ //guts }
 }

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

Теперь я нарушил принцип СУХОГО, и я управляю и изменяю один и тот же код в нескольких файлах. Я намереваюсь иметь больше классов, таких как лодки, лошади или что-то еще.

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

abstract class content {
    $title;
    $description


    function get_data($website){  }

    function common_function2() { }
    function common_function3() { }
 }


class calendar_event extends content {

    $start_date;

    function validate_dates(){  }
 }

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

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

Благодарность!

user66662
источник
Есть много хороших примеров в Интернете. Я думаю, что это один из них. javapapers.com/core-java/abstract-and-interface-core-java-2/…
Шива

Ответы:

26

С точки зрения непрофессионала:

Интерфейсы предназначены для типа «можно сделать / можно рассматривать как» .

Абстрактные (а также конкретные) классы предназначены для «это» своего рода отношений.

Посмотрите на эти примеры:

class Bird extends Animal implements Flight;
class Plane extends Vehicle implements Flight, AccountableAsset;
class Mosquito extends Animal implements Flight;
class Horse extends Animal;
class RaceHorse extends Horse implements AccountableAsset;
class Pegasus extends Horse implements Flight;

Bird, MosquitoИ Horse являются Animals . Они связаны. Они наследуют общие методы от животных, как eat(), metabolize() and reproduce(). Возможно, они переопределяют эти методы, добавляя к ним немного больше, но они используют преимущества поведения по умолчанию, реализованного в Animal, напримерmetabolizeGlucose().

Planeне имеет отношения к Bird, Mosquitoили Horse.

Flightреализуется различными, не связанными классами, как Birdи Plane.

AccountableAssetтакже реализуется различными, не связанными классами, такими как Planeи RaceHorse.

Horse не осуществляет полет.

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

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

Например, вы можете иметь программную сумму значения группы AccountableAssetsнезависимо от того, кем они являются RaceHorsesили Planes.

Тулаинс Кордова
источник
Удивительный. Интерфейс обеспечивает определенный раздел функциональности, который устанавливает, can do/can be treated asгде абстрактные классы действуют как фундаментальные!
Абхирой Панвар,
13

Вы могли бы вывести ответ логически, так как вы, кажется, знаете о различиях между ними.

Интерфейсы определяют общий контракт. Такой как интерфейс под названием IAnimal, где все животные имеют общие функции, такие как Eat (), Move (), Attack () и т. Д. Хотя все они имеют одни и те же функции, все или большинство из них имеют разные способы (реализации) достижения Это.

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

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

Кроме того, в Google нет недостатка в результатах.

Dante
источник
3

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

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

Надеюсь, это поможет, но есть много информации об этом онлайн, Лео

RealityDysfunction
источник
2
Classes cannot have multiple inheritance- Верно для языков, таких как Java и C #, не верно для C ++.
Роберт Харви
3

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

Интерфейсы позволяют повторно использовать клиентский код с различными реализациями. Клиент вашего класса get_data ($ website) не заботится об элементах $ title или $ description. Он просто хочет, чтобы ваш контент загружал данные. Если у вас есть разные типы контента, некоторые из которых требуют описания $, а некоторые нет, вы можете предоставить класс ContentInterface, который определяет только сигнатуру ваших дочерних классов. Теперь клиент может иметь любое количество различных контентов, не зная точно, как они работают. Принцип подстановки Лискова - хорошая вещь для изучения этой идеи. Мне также нравится, что дядя Боб пишет на эту тему. Интерфейсы очень важны для модульного тестирования, и создание интерфейсов - хорошая привычка для изучения.

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

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

Бен
источник
3

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

Если вы хотите сделать упор на повторное использование и полиморфное поведение, выберите абстрактный класс. Например, сотрудники разных типов имеют разные положения, но все получают несколько общих. Таким образом, абстрактный класс подходит для его представления, поскольку общие черты могут быть выражены в базовом абстрактном классе, Employeeа различие может быть реализовано в производных классах, таких как Managerили Workerт. Д.

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

Тед
источник
-3
  1. Основное отличие состоит в том, что методы интерфейса Java неявно абстрактны и не могут иметь реализации. Абстрактный класс Java может иметь методы экземпляров, которые реализуют поведение по умолчанию.
  2. Переменные, объявленные в интерфейсе Java, по умолчанию являются окончательными. Абстрактный класс может содержать неконечные переменные.
  3. Члены интерфейса Java являются общедоступными по умолчанию. Абстрактный класс Java может иметь обычные разновидности членов класса, такие как private, protected и т. Д.
  4. Java-интерфейс должен быть реализован с использованием ключевого слова «Implements»; Абстрактный класс Java должен быть расширен с помощью ключевого слова «extends».
  5. Интерфейс может расширять другой интерфейс Java, только абстрактный класс может расширять другой класс Java и реализовывать несколько интерфейсов Java.
  6. Класс Java может реализовывать несколько интерфейсов, но он может расширять только один абстрактный класс.
  7. Интерфейс абсолютно абстрактный и не может быть создан; Абстрактный класс Java также не может быть создан, но может быть вызван, если существует main ().
  8. По сравнению с абстрактными классами Java, интерфейсы Java медленны, так как требуют дополнительной косвенности.
  9. Интерфейс и абстрактный класс в Java - это то, что вы не можете создать не абстрактный метод в интерфейсе, каждый метод в интерфейсе по умолчанию является абстрактным, но вы можете создать не абстрактный метод в абстрактном классе.
  10. Абстрактный класс и интерфейс в Java таковы, что интерфейсы лучше подходят для объявления типов, а абстрактный класс больше подходит для повторного использования кода и перспективы развития.
Sakina.A
источник