Я пытаюсь изучить ООП в PHP, и у меня есть путаница в интерфейсах и абстрактных классах. Оба они не содержат реализаций, только определений и должны выполняться через их подклассы. Какая часть абстрактных классов четко отличает их от интерфейсов? Кроме того, из-за их очевидного сходства, исходя из каких причин я должен решить использовать один над другим?
Можно создавать абстрактные классы, которые содержат конкретные элементы, такие как методы или свойства. Вы все равно не можете создать экземпляр абстрактного класса напрямую, но любые созданные подклассы могут извлечь выгоду из реализованных элементов, определенных в абстрактном классе.
Для сравнения, интерфейс не содержит никакой логики реализации. Для каждого класса реализации не требуется реализация всех членов, определенных в интерфейсе.
В терминах того, как я рассматриваю различия, подкласс класса абстрактного типа – это класс этого типа. например, Dog
– это Animal
. Я вижу интерфейс как отношения. например, ICanDisplayImages
говорит мне, что класс реализации может отображать изображения, но ничего не говорит о том, что класс фактически представляет.
abstract
класс формирует связь между собой и подклассом, тогда как interface
создает следующую взаимосвязь. Таким образом, абстрактные классы гораздо более конкретны, чем интерфейсы, и они могут также содержать конкретные реализации (например, методы шаблонов ), а интерфейс определяет контрактный набор методов, которым должен следовать класс реализации. Это гораздо более высокий уровень абстракции, поскольку класс реализации не обязательно должен быть абстрактного класса. Используйте его для стандартизации вашего API.
Связанные вопросы: https://stackoverflow.com/search?q=abstract+vs+interface
Помимо философии ООП, описанной в других ответах, я думаю, что основное использование абстрактного класса – это скелет.
Это полезно, когда вы разрабатываете приложение или работаете с командой, потому что у вас есть базовый код для работы и расширения, он близок к интерфейсу, но с более сложным рабочим процессом.
Оба они не содержат реализаций.
Абстрактный класс может реализовать все или только часть методов. Но основная философия – это расширение существующего абстрактного класса путем добавления новых методов в дочерние классы (которые расширяют базовую функциональность).
В дочернем классе вы можете расширить только один класс (абстрактный класс). Абстрактный класс определяет функциональность, которую вы должны реализовать или просто расширять другими методами в дочерних классах.
Интерфейсы используются для определения поведения класса. Вы можете реализовать более одного интерфейса (и сказать, что мой дочерний класс должен делать это, это и эти тиги!), Но вы можете расширить только один абстрактный класс.
Основное различие между абстрактным классом и интерфейсом заключается в том, что интерфейс определяет общие поведения, где абстрактный класс является базовым классом для наследования. Другими словами, абстрактный класс определяет некоторый основной набор методов и свойств, которые могут быть разделены подклассами. Рассмотрим класс, который определяет лицензию. Все лицензии имеют идентификационный номер определенного типа и выдаются отдельным лицам или группам. Класс лицензии может быть расширен с помощью класса License License, класса License License и класса Hunting License и т. Д. Основная причина заключается в том, что абстрактная абстрактность класса лицензии будет заключаться в том, что она определяет абстрактную идею лицензии. Существует не такая вещь, как лицензия, поэтому, объявив абстрактную категорию, она не может быть создана.
С другой стороны, интерфейс не определяет объект вообще. Он определяет сигнатуры методов. Любой не-абстрактный класс, реализующий интерфейс, должен обеспечить реализацию для всех методов интерфейса. Преимущество здесь заключается в том, что метод обеспечивает общий интерфейс для разных типов объектов, например, compareTo () выглядит одинаково при использовании со строками или любым другим объектом.
Абстрактный класс может содержать реализации метода, если метод не определен как абстрактный. Если метод определен как абстрактный, он не содержит реализацию, но его необходимо реализовать его наследниками. Абстрактный класс не может быть создан, но только унаследован от него, чтобы наследник позволял ему использовать его поведение.
Интерфейс определяет только сигнатуры методов, и любой класс, наследующий от него, должен реализовывать все методы, содержащиеся в интерфейсе.
Обычно интерфейсы используются для определения контрактов, поэтому вы получаете проверку типов. Существует также стиль программирования, называемый «программирование против интерфейсов», что является хорошей идеей. См. Принцип инверсии зависимостей :
A. Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций.
B. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций ».
Поэтому, если вы определяете функции и методы, вместо типа, намекающего на классы, вы просто намекаете на интерфейсы.
Вот пример. Предположим, вы определяете интерфейсы для входных потоков и потоков вывода следующим образом:
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));}}
в// 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
бесплатно!