Как ответить
Абстрактный класс и интерфейс решают разные задачи проектирования. Если упростить: интерфейс определяет, что объект умеет делать (контракт), а абстрактный класс описывает, кем объект является (базовая сущность). Главное техническое отличие в том, что класс может наследоваться только от одного родителя, но реализовывать сколько угодно интерфейсов.
Абстрактный класс стоит выбирать, когда у группы объектов есть общая идентичность и общая логика, которую нужно вынести в одно место. Например, в системе складского учета у нас есть разные типы товаров. У них будут общие свойства (артикул, цена) и методы (изменение остатка), которые работают одинаково для всех.
abstract class Product {
protected string $sku;
protected float $price;
public function updatePrice(float $newPrice): void {
$this->price = $newPrice;
}
abstract public function calculateTax(): float;
}
Интерфейс нужен, когда мы хотим гарантировать наличие определенного поведения у классов, которые могут быть вообще не связаны друг с другом. Например, интерфейс Exportable может быть и у товара, и у пользователя, и у логов системы. Им не нужно общее состояние, им нужно просто уметь превращаться в JSON или XML.
interface Exportable {
public function toFormat(): string;
}
class User implements Exportable {
public function toFormat(): string { return "json_user_data"; }
}
class Order implements Exportable {
public function toFormat(): string { return "json_order_data"; }
}
Основные критерии выбора:
- Наследование состояния: Если нужны поля (свойства) и модификаторы доступа (protected, private), используйте абстрактный класс. В интерфейсах (в большинстве языков) нельзя хранить состояние объекта.
- Множественная реализация: Если класс должен поддерживать несколько разных функций (например, логироваться, клонироваться и сериализоваться), это делается через интерфейсы.
- Готовая логика: Если вы хотите дать наследникам не только сигнатуры методов, но и их базовую реализацию, чтобы избежать дублирования кода, подходит абстрактный класс.
- Связанность системы: Интерфейсы создают более слабую связанность (loose coupling), что упрощает тестирование и замену компонентов.
В современной разработке чаще советуют отдавать предпочтение интерфейсам (принцип Composition over Inheritance), так как это делает архитектуру гибче. Абстрактные классы хороши на нижних уровнях системы для создания каркаса конкретного модуля.