Декоратор (англ. Decorator) належати до класу структурних шаблонів. Він використовується для динамічного розширення
функціональності об’єкта. Є гнучкою альтернативою успадкування.
Сенс полягає в тому, щоб можна було безболісно комбінувати різні декоратори у довільному порядку,
навішуючи їх на різні об’єкти. До певної міри, це схоже на технологію traits, за винятком того,
що декоратори динамічно навішуються на об’єкт, а traits - статично на клас.
Наприклад, ми маємо клас “Cheeseburger”, який реалізує інтерфейс “BurgerInterface”.
Тут ми помічаємо, що в класі “Cheeseburger” не вистачає сиру. Це основний інгредієнт чизбургеру, і добре б нам дописати його в клас.. Але уявімо, що переписувати клас ми не можемо. “Давайте успадковуємо Cheeseburger і розширимо його”, скажете ви.
А якщо нам потрібно ще щось додати до Cheeseburger? Знову успадкування.
А якщо потрібно це все поєднати і ще щось додати? Знову успадкуємо. Потім знову і знову…
Декоратор допомагає нам зробити це дедалі гнучкіше.
Оскільки наш абстрактний декоратор AbstractDecorator реалізує інтерфейс BurgerInterface,
ми можемо розширювати його лише на рівні абстракції.
Додамо сир засобами CheeseburgerCheeseDecorator.
Наш декоратор (спадкоємець AbstractDecorator) у конструктор чекає об’єкт типу BurgerInterface.
Як згадувалося вище, AbstractDecorator реалізує інтерфейс BurgerInterface. Але метод BurgerInterface->makeBurger()
він не реалізує, а позначає як абстрактний. Це означає, що спадкоємці мають реалізувати його.
Ось у ньому ми декоруватимемо наш чизбургер.
А тепер давайте змінимо соус у чизбургері.
Створюємо новий декоратор CheeseburgerSauceDecorator (спадкоємець AbstractDecorator).
Тепер ми можемо розширювати будь-який об’єкт типу ** BurgerInterface .
Це може бути як вихідний чизбургер без сиру (об’єкт **Cheeseburger->makeBurger()), так і вже декорований з сиром (CheeseburgerCheeseDecorator->makeBurger()).