Какова цель абстрактных классов?

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

Ответ 1

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

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

В терминах того, как я рассматриваю различия, подкласс класса abstract - это класс этого типа. например Dog является Animal. Я вижу интерфейс как отношения. например ICanDisplayImages говорит мне, что класс реализации может отображать изображения, но ничего не говорит о том, что класс фактически представляет.

Ответ 2

An abstract класс формирует отношения is-a между собой и подклассом, а interface создает следующее отношение. Таким образом, абстрактные классы гораздо более конкретны, чем интерфейсы, и они могут также содержать конкретные реализации (например, Template methods), в то время как интерфейс определяет контрактный набор методов, которым должен следовать класс реализации. Это гораздо более высокий уровень абстракции, поскольку класс реализации не обязательно должен быть абстрактного класса. Используйте его для стандартизации вашего API.

Похожие вопросы: https://stackoverflow.com/search?q=abstract+vs+interface

Ответ 3

Оба они не содержат реализаций.

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

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

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

Ответ 4

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

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

Ответ 5

Основное различие между абстрактным классом и интерфейсом заключается в том, что интерфейс определяет общие поведения, где абстрактный класс является базовым классом для наследования. Другими словами, абстрактный класс определяет некоторый основной набор методов и свойств, которые могут быть разделены подклассами. Рассмотрим класс, который определяет лицензию. Все лицензии имеют идентификационный номер определенного типа и выдаются отдельным лицам или группам. Класс лицензии может быть расширен классом лицензии драйвера, классом лицензии на велосипед и классом лицензии на охоту и т.д. Основная причина заключается в том, что абстрактная абстрактность класса лицензии будет заключаться в том, что она определяет абстрактную идею лицензии. Существует не такая вещь, как лицензия, поэтому, объявляя абстрактный класс, он не может быть создан. С другой стороны, интерфейс не определяет объект вообще. Он определяет сигнатуры методов. Любой не-абстрактный класс, реализующий интерфейс, должен обеспечить реализацию для всех методов интерфейса. Преимущество здесь заключается в том, что этот метод обеспечивает общий интерфейс для различных типов объектов, например. compareTo() выглядит одинаково при использовании со строками или любым другим объектом.

Ответ 6

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

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

Ответ 7

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

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

В. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций ".

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

Вот пример. Скажем, вы определяете интерфейсы для входных потоков и потоков вывода следующим образом:

interface OutputStream{
  write($string); // Writes a string to the output.
  close(); // Closes the output stream.
}

interface InputStream{
  read($length); // Reads at most $length characters.
  eof(); // TRUE, if the input stream is empty.
}

Теперь вы можете создать функцию или метод copy, который копирует полный вывод потока на вход без каких-либо из них:

// 50 is just chosen randomly.
function copy(InputStream $input, OutputStream $output){
  while(!$input->eof()){
    $output->write($input->read(50));}}

Поздравляем, ваша реализация copy теперь работает для каждой комбинации потока ввода и вывода, даже не реализуя ее.

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

Опять же, пример. Скажем, вы хотите иметь выходные потоки. Вам нужен метод write($s), который записывает строку в вывод, и вы хотите использовать метод writeLine($s), который записывает строку и дополнительную строку новой строки в вывод. Тогда это будет уместно:

abstract class AbstractOutputStream{
  public function writeLine($s){
    $this->write($s."\n");}}

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