Ответ
Декоратор — это структурный паттерн, позволяющий динамически добавлять объектам новую функциональность, оборачивая их в объекты-декораторы. Основная проблема, которую он решает — расширение поведения объекта без изменения его исходного кода и без создания подклассов.
Пример с кэшированием:
interface DataProvider {
public function fetchData(): array;
}
class DbDataProvider implements DataProvider {
public function fetchData(): array {
return ['data' => 'from db'];
}
}
class CacheDecorator implements DataProvider {
private $provider;
private $cache;
public function __construct(DataProvider $provider) {
$this->provider = $provider;
}
public function fetchData(): array {
if ($this->cache) return $this->cache;
$this->cache = $this->provider->fetchData();
return $this->cache;
}
}
// Использование
$provider = new CacheDecorator(new DbDataProvider());
$data = $provider->fetchData(); // Будет закешировано
Плюсы:
- Гибкость: можно комбинировать декораторы
- Открытость/закрытость: не изменяем исходный класс
- Чистая композиция вместо наследования
Ответ 18+ 🔞
А, декоратор, ёпта! Это ж как на новогоднюю ёлку гирлянды вешать, только для кода. Суть в чём, чувак? Ну вот представь, у тебя есть объект, простой, как пять копеек. А тебе вдруг надо, чтобы он ещё и кэшировал, и логировал, и по сети данные шифровал перед отправкой. И что, на каждый чих новый класс плодить? Ёб твою мать, так до завтра кодить будешь, а потом ещё и поддерживать эту манду с ушами.
Вот тут декоратор и выручает. Берёшь свой базовый объект, и просто, как шубу, оборачиваешь его в другой, который добавляет одну новую фишку. А потом этот обёрнутый — в следующий, который добавляет ещё одну. Получается такая матрёшка, хитрая жопа, но чертовски удобная.
Смотри на примере, тут всё понятно становится. Вот есть интерфейс DataProvider. Просто говорит: «Умею данные отдавать, да похуй откуда».
interface DataProvider {
public function fetchData(): array;
}
Дальше идёт честный работяга, который тащит данные прямиком из базы. Без фокусов.
class DbDataProvider implements DataProvider {
public function fetchData(): array {
return ['data' => 'from db'];
}
}
И вот появляется наш герой — CacheDecorator. Это он и есть, тот самый декоратор, полупидор в хорошем смысле. Его задача — добавить кэширование ЛЮБОМУ провайдеру, который засунешь ему в конструктор.
class CacheDecorator implements DataProvider {
private $provider;
private $cache;
public function __construct(DataProvider $provider) {
$this->provider = $provider; // Запоминаем, кого оборачиваем
}
public function fetchData(): array {
// Если в кэше уже есть — нахуй не паримся, отдаём оттуда
if ($this->cache) return $this->cache;
// Если нет — идём к оригинальному провайдеру, берём у него
$this->cache = $this->provider->fetchData();
return $this->cache;
}
}
А использование — это просто песня. Хочешь кэширующего провайдера? Без проблем, оборачивай.
$provider = new CacheDecorator(new DbDataProvider());
$data = $provider->fetchData(); // Первый раз сходит в базу, второй — уже из кэша
А завтра понадобится ещё и логирование? Да хуй с горы! Сделаешь LoggingDecorator и обернёшь им всё то же самое. Получится new LoggingDecorator(new CacheDecorator(new DbDataProvider())). Каждый слой делает своё дело, не лезет в чужое, и все довольны.
Пиздец какие плюсы:
- Гибкость, блядь, овердохуища: Собираешь функциональность, как из Лего. Нужен кэш, но без логирования? Убрал один слой — и готово. Волнение ебать от такой простоты.
- Принцип открытости/закрытости: Исходный класс
DbDataProviderты не трогаешь вообще. Он как был святым, так и остался. Новую функциональность добавляешь снаружи, обёртками. Доверия ебать ноль к тем, кто лезет в рабочий код с кривыми правками. - Композиция вместо наследования: Не нужно создавать класс
DbDataProviderWithCacheAndLogging, который унаследует всё от всех и превратится в пидараса шерстяного, которого и тронуть страшно. Всё чисто, всё на совести.
В общем, паттерн — ядрёна вошь. Когда нужно на лету прикрутить фичи к объекту, не разбирая его на запчасти, он выручает по полной. Главное — не увлечься и не сделать обёрток на двадцать слоёв, а то отладка превратится в кромешный ад.