Оглавление:
Карта сайта:
Оглавление:
Карта сайта:
Шаблон декоратора позволяет динамически изменять поведение объекта во время выполнения, заключая его в объект класса
декоратора.
Возможность динамически добавлять новые обязанности, не прибегая к порождению подклассов, облегчает понимание основных
обязанностей объектов и не запутывает основную бизнес-логику информационных систем.
Можно добавлять и удалять обязанности во время выполнения программы, в то время как при использовании наследования надо
было бы создавать новый класс для каждой дополнительной обязанности.
Данный шаблон позволяет не создавать классов, перегруженных методами. Новые обязанности можно добавлять только по мере
необходимости, не перегружая программное обеспечение лишними классами.
Использование:
поэтому клиентам без разницы, с чем работать – с обычным объектом данных или с обёрнутым.
Расширить такие классы можно только с помощью Декоратора.
Преимущества:
Недостатки:
Связи с другими паттернами
Адаптер меняет интерфейс существующего объекта. Декоратор улучшает другой объект без изменения его интерфейса. Причём
Декоратор поддерживает рекурсивную вложенность, чего не скажешь об Адаптере.
Адаптер предоставляет классу альтернативный интерфейс. Декоратор предоставляет расширенный интерфейс. Заместитель
предоставляет тот же интерфейс.
Цепочка обязанностей и Декоратор имеют очень похожие структуры. Оба паттерна базируются на принципе рекурсивного
выполнения операции через серию связанных объектов. Но есть и несколько важных отличий.
Обработчики в Цепочке обязанностей могут выполнять произвольные действия, независимые друг от друга, а также в любой
момент прерывать дальнейшую передачу по цепочке. С другой стороны Декораторы расширяют какое-то определённое действие,
не ломая интерфейс базовой операции и не прерывая выполнение остальных декораторов.
Компоновщик и Декоратор имеют похожие структуры классов из-за того, что оба построены на рекурсивной вложенности. Она
позволяет связать в одну структуру бесконечное количество объектов.
Декоратор оборачивает только один объект, а узел Компоновщика может иметь много детей. Декоратор добавляет вложенному
объекту новую функциональность, а Компоновщик не добавляет ничего нового, но «суммирует» результаты всех своих детей.
Но они могут и сотрудничать: Компоновщик может использовать Декоратор, чтобы переопределить функции отдельных частей
дерева компонентов.
Архитектура, построенная на Компоновщиках и Декораторах, часто может быть улучшена за счёт внедрения Прототипа. Он
позволяет клонировать сложные структуры объектов, а не собирать их заново.
Стратегия меняет поведение объекта «изнутри», а Декоратор изменяет его «снаружи».
Декоратор и Заместитель имеют схожие структуры, но разные назначения. Они похожи тем, что оба построены на принципе
композиции и делегируют работу другим объектам. Паттерны отличаются тем, что Заместитель сам управляет жизнью сервисного
объекта, а обёртывание Декораторов контролируется клиентом.
<?php interface Worker { public function countSalary(): int; } abstract class WorkerDecorator implements Worker { public Worker $worker; public function __construct(Worker $worker) { $this->worker = $worker; } } class Developer implements Worker { public function countSalary(): int { return 20 * 3000; } } class DeveloperOverTime extends WorkerDecorator { public function countSalary(): int { return $this->worker->countSalary() + $this->worker->countSalary() * 0.2; } } $developer = new Developer(); $developerOverTime = new DeveloperOverTime($developer); echo $developer->countSalary(); // 60000 echo $developerOverTime->countSalary(); // 72000 // ----------- 2 ----------- interface Coffee { public function getCost(); public function getDescription(); } class SimpleCoffee implements Coffee { public function getCost() { return 10; } public function getDescription() { return 'Simple coffee'; } } class MilkCoffee implements Coffee { protected $coffee; public function __construct(Coffee $coffee) { $this->coffee = $coffee; } public function getCost() { return $this->coffee->getCost() + 2; } public function getDescription() { return $this->coffee->getDescription() . ', milk'; } } class WhipCoffee implements Coffee { protected $coffee; public function __construct(Coffee $coffee) { $this->coffee = $coffee; } public function getCost() { return $this->coffee->getCost() + 5; } public function getDescription() { return $this->coffee->getDescription() . ', whip'; } } $someCoffee = new SimpleCoffee(); echo $someCoffee->getCost(); // 10 echo $someCoffee->getDescription(); // Simple Coffee $someCoffee = new MilkCoffee($someCoffee); echo $someCoffee->getCost(); // 12 echo $someCoffee->getDescription(); // Simple Coffee, milk $someCoffee = new WhipCoffee($someCoffee); echo $someCoffee->getCost(); // 17 echo $someCoffee->getDescription(); // Simple Coffee, milk, whip // ----------- 3 ----------- interface Booking { public function calculatePrice(): int; public function getDescription(): string; } // Шаблон "Декоратор" хранит ссылку на объект (компонент), определяет его интерфейс и переадресует на него рабочие запросы. abstract class BookingDecorator implements Booking { public function __construct(protected Booking $booking) { } } // Системный компонент определяет интерфейс объекта, на который могут быть динамически возложены дополнительные обязанности class DoubleRoomBooking implements Booking { public function calculatePrice(): int { return 40; } public function getDescription(): string { return 'double room'; } } // Конкретный компонент определяет объект, на который возлагаются дополнительные обязанности. class ExtraBed extends BookingDecorator { private const PRICE = 30; public function calculatePrice(): int { return $this->booking->calculatePrice() + self::PRICE; } public function getDescription(): string { return $this->booking->getDescription() . ' with extra bed'; } } class WiFi extends BookingDecorator { private const PRICE = 2; public function calculatePrice(): int { return $this->booking->calculatePrice() + self::PRICE; } public function getDescription(): string { return $this->booking->getDescription() . ' with wifi'; } } $booking = new DoubleRoomBooking(); echo $booking->calculatePrice(); // 4 echo $booking->getDescription(); // double room $booking2 = new DoubleRoomBooking(); $booking2 = new WiFi($booking2); echo $booking2->calculatePrice(); // 42 echo $booking2->getDescription(); // double room with wifi $booking3 = new DoubleRoomBooking(); $booking3 = new WiFi($booking); $booking3 = new ExtraBed($booking); echo $booking3->calculatePrice(); // 72 echo $booking3->getDescription(); // double room with wifi with extra bed