Menu
Coddy logo textTech

Интерфейс и абстрактный класс

Часть раздела Объектно-ориентированное программирование путешествия по 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";
    }
}

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

challenge icon

Задание

Легко

Давайте создадим систему транспортных средств, которая демонстрирует, когда использовать абстрактный class, а когда — interface, и как эффективно сочетать оба подхода.

Вы создадите систему, в которой транспортные средства используют общие properties через наследование, но также могут получать дополнительные возможности через interfaces. Это отражает решения, принимаемые при проектировании реальных систем: автомобиль «является» транспортным средством (наследование), но также «обладает возможностью» заправляться (interface).

Организуйте код в четырех файлах:

  • Refuelable.php: Define interface Refuelable с единственной сигнатурой method: refuel($amount). Эта возможность может применяться к любому class, которому требуется заправка, независимо от его иерархии наследования.
  • Vehicle.php: Define абстрактный class Vehicle, который предоставляет общую функциональность для всех транспортных средств. В нем должны быть protected property $brand и protected property $fuelLevel (начиная со значения 0). constructor accepts название бренда. Добавьте конкретный method getBrand(), который возвращает бренд, конкретный method getFuelLevel(), который возвращает текущий уровень топлива, и абстрактный method drive(), который дочерние class должны Implement.
  • Car.php: Создайте class Car, который extends Vehicle и implements Refuelable. В начале подключите оба обязательных файла. constructor accepts бренд и passes его в parent constructor. Implement drive(), чтобы он возвращал "[brand] car is driving". Implement refuel($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() с количеством топлива на второй строке
?>
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор PHP