Декораторы в PHP, подробно с примерами
Декораторы в программировании — это структурный шаблон проектирования, который предоставляет гибкий альтернативный способ расширения функциональности существующего объекта.
В PHP декораторы можно реализовать с использованием интерфейсов и наследования.
Допустим, у нас есть интерфейс Coffee:
interface Coffee
{
public function getCost();
public function getDescription();
}
Теперь создадим базовый класс SimpleCoffee, который реализует интерфейс Coffee:
class SimpleCoffee implements Coffee
{
public function getCost()
{
return 10;
}
public function getDescription()
{
return 'Simple coffee';
}
}
Чтобы расширить функциональность SimpleCoffee, мы создадим абстрактный класс декоратора CoffeeDecorator:
abstract class CoffeeDecorator implements Coffee
{
protected $coffee;
public function __construct(Coffee $coffee)
{
$this->coffee = $coffee;
}
public function getCost()
{
return $this->coffee->getCost();
}
public function getDescription()
{
return $this->coffee->getDescription();
}
}
Теперь мы можем создать разные декораторы, расширяющие функциональность класса SimpleCoffee.
Например, создадим декораторы для добавления молока и сахара:
class MilkDecorator extends CoffeeDecorator
{
public function getCost()
{
return parent::getCost() + 2;
}
public function getDescription()
{
return parent::getDescription() . ', with milk';
}
}
class SugarDecorator extends CoffeeDecorator
{
public function getCost()
{
return parent::getCost() + 1;
}
public function getDescription()
{
return parent::getDescription() . ', with sugar';
}
}
Теперь мы можем использовать декораторы для расширения функциональности SimpleCoffee:
$coffee = new SimpleCoffee();
echo $coffee->getCost(); // 10
echo $coffee->getDescription(); // Simple coffee
$coffee = new MilkDecorator($coffee);
echo $coffee->getCost(); // 12
echo $coffee->getDescription(); // Simple coffee, with milk
$coffee = new SugarDecorator($coffee);
echo $coffee->getCost(); // 13
echo $coffee->getDescription(); // Simple coffee, with milk, with sugar
Это позволяет избежать перегрузки классов и сохранить модульность кода.