Интерфейс и абстрактный класс
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy. Урок 30 из 91.
Теперь, когда ты изучил интерфейсы и абстрактные классы, давай разберёмся, когда использовать каждый из них. Хотя они могут казаться похожими, они служат разным целям и обладают разными возможностями.
| Возможность | Интерфейс | Абстрактный class |
|---|---|---|
| Методы | Только сигнатуры методов | Абстрактные и конкретные методы |
| Свойства | Только константы | Может иметь свойства |
| Множественное наследование | class может реализовать несколько | class может расширять только один |
| Конструктор | Может объявить сигнатуру __construct (без тела) | Может определить constructor с телом |
Используйте interface, когда хотите определить контракт, который могут выполнять несвязанные классы. Например, и Printer, и Logger могут реализовывать интерфейс Writable, даже если у них нет общего предка.
Используй abstract class, когда у тебя есть связанные классы, которые используют общий код. Если твоим классам Dog и Cat нужна одна и та же реализация метода eat(), абстрактный класс Animal позволяет написать этот код один раз.
Вы также можете сочетать оба подхода. Класс может расширять абстрактный класс, одновременно реализуя несколько интерфейсов:
<?php
abstract class Animal {
protected $name;
public function eat() {
return $this->name . " is eating";
}
}
interface Swimmable {
public function swim();
}
class Duck extends Animal implements Swimmable {
public function __construct($name) {
$this->name = $name;
}
public function swim() {
return $this->name . " is swimming";
}
}
Ключевой момент: Выбирай интерфейсы для определения возможностей в несвязанных классах. Выбирай абстрактные классы, когда нужно совместно использовать код в связанных классах.
Задание
ЛегкоДавайте создадим систему транспортных средств, которая демонстрирует, когда использовать абстрактный class, а когда — interface, и как эффективно сочетать оба подхода.
Вы создадите систему, в которой транспортные средства используют общие properties через наследование, но также могут получать дополнительные возможности через interfaces. Это отражает решения, принимаемые при проектировании реальных систем: автомобиль «является» транспортным средством (наследование), но также «обладает возможностью» заправляться (interface).
Организуйте код в четырех файлах:
Refuelable.php: Define interfaceRefuelableс единственной сигнатурой method:refuel($amount). Эта возможность может применяться к любому class, которому требуется заправка, независимо от его иерархии наследования.Vehicle.php: Define абстрактный classVehicle, который предоставляет общую функциональность для всех транспортных средств. В нем должны быть protected property$brandи protected property$fuelLevel(начиная со значения 0). constructor accepts название бренда. Добавьте конкретный methodgetBrand(), который возвращает бренд, конкретный methodgetFuelLevel(), который возвращает текущий уровень топлива, и абстрактный methoddrive(), который дочерние class должны Implement.Car.php: Создайте classCar, который extendsVehicleи implementsRefuelable. В начале подключите оба обязательных файла. constructor accepts бренд и passes его в parent constructor. Implementdrive(), чтобы он возвращал"[brand] car is driving". Implementrefuel($amount), чтобы он добавлял amount к уровню топлива и возвращал"[brand] refueled to [fuelLevel] liters".main.php: Подключите файл Car. Вы получите два входных значения: название бренда и количество топлива (преобразуйте его в integer). СоздайтеCarс указанным брендом. Print результатdrive()в первой строке, затем Print результатrefuel()с количеством топлива во второй строке.
Это задание иллюстрирует ключевое различие: абстрактный class Vehicle использует общий код и устанавливает отношение «является», тогда как interface Refuelable добавляет возможность, которая может применяться к другим несвязанным class (например, генератору или лодке), не требуя, чтобы они были транспортными средствами.
Попробуйте сами
<?php
require_once 'Car.php';
// Прочитать ввод
$brand = trim(fgets(STDIN));
$fuelAmount = intval(trim(fgets(STDIN)));
// TODO: Создать Car с brand
// TODO: Вывести результат drive() на первой строке
// TODO: Вывести результат refuel() с количеством топлива на второй строке
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Повторение — простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыПовторение — иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateМодификаторы доступа подробноГеттеры и сеттерыСокрытие информацииПродвижение конструктора (8.0)Повторение — система учёта студентов2Пространства имён и автозагрузка
Введение в пространства имёнКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerПовторение — структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс и абстрактный классАннотация типов с интерфейсамиПовторение — калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeПовторение — пользовательская коллекция3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищённые свойстваСвойства только для чтения (PHP 8.1)Повторение — менеджер банковского счёта6Полиморфизм
Повторение переопределения методовПолиморфизм через интерфейсыАннотации типов и объединённые типыПозднее статическое связываниеПовторение — обработчик платежей9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования, часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн StrategyПотренируйтесь самостоятельно: Онлайн-компилятор PHP