Назад к вопросам
Middle
107
questionbank

Как работает декоратор в PHP?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Паттерн "Декоратор" динамически добавляет новое поведение существующему объекту, оборачивая его в другой объект, называемый декоратором.

  • Компоненты:

    • Интерфейс (Component): Объявляет общие методы для исходного объекта и его декораторов.
    • Конкретный Компонент (Concrete Component): Основной объект, который необходимо декорировать.
    • Базовый Декоратор (Decorator): Абстрактный класс или интерфейс, который содержит ссылку на объект интерфейса (Component) и реализует его методы, обычно делегируя вызов этому объекту.
    • Конкретные Декораторы (Concrete Decorators): Реализуют новые возможности, дополняя или изменяя поведение базового компонента.
  • Принцип работы:

    • Декоратор содержит ссылку на объект, который он декорирует (композиция).
    • Декоратор имеет тот же интерфейс, что и декорируемый объект.
    • При вызове метода у декоратора, он либо выполняет дополнительную логику до или после вызова соответствующего метода у декорируемого объекта, либо полностью его заменяет (хотя последнее не является типичным использованием).
  • Преимущества:

    • Позволяет добавлять функциональность к объектам во время выполнения, а не в статическом виде наследования.
    • Избегает "взрыва" иерархии классов при комбинировании множества различных поведений.
    • Позволяет создавать гибкие комбинации поведения.
  • Пример:

<?php

// Интерфейс Компонента
interface Coffee {
    public function getCost(): float;
    public function getDescription(): string;
}

// Конкретный Компонент
class SimpleCoffee implements Coffee {
    public function getCost(): float {
        return 5.0;
    }

    public function getDescription(): string {
        return "Обычный кофе";
    }
}

// Базовый Декоратор
abstract class CoffeeDecorator implements Coffee {
    protected Coffee $coffee;

    public function __construct(Coffee $coffee) {
        $this->coffee = $coffee;
    }

    public function getCost(): float {
        return $this->coffee->getCost();
    }

    public function getDescription(): string {
        return $this->coffee->getDescription();
    }
}

// Конкретный Декоратор: Добавление молока
class MilkDecorator extends CoffeeDecorator {
    public function getCost(): float {
        return parent::getCost() + 2.0;
    }

    public function getDescription(): string {
        return parent::getDescription() . ", с молоком";
    }
}

// Конкретный Декоратор: Добавление сахара
class SugarDecorator extends CoffeeDecorator {
    public function getCost(): float {
        return parent::getCost() + 1.0;
    }

    public function getDescription(): string {
        return parent::getDescription() . ", с сахаром";
    }
}

// Использование:
// Создаем обычный кофе
$coffee = new SimpleCoffee();
echo $coffee->getDescription() . " - " . $coffee->getCost() . "\n"; // Обычный кофе - 5

// Добавляем молоко
$coffeeWithMilk = new MilkDecorator($coffee);
echo $coffeeWithMilk->getDescription() . " - " . $coffeeWithMilk->getCost() . "\n"; // Обычный кофе, с молоком - 7

// Добавляем еще и сахар
$coffeeWithMilkAndSugar = new SugarDecorator($coffeeWithMilk);
echo $coffeeWithMilkAndSugar->getDescription() . " - " . $coffeeWithMilkAndSugar->getCost() . "\n"; // Обычный кофе, с молоком, с сахаром - 8