Wzorzec Dekorator zalicza się do strukturalnych wzorców projektowych i pozwala rozbudować istniejącą strukturę o nowe funkcjonalności, które nie wpłyną na inne obiekty (komponenty). Można w pewnym sensie porównać go do dziedziczenia, z tym, że zapewnia większą elastyczność. Poza tym dodaje funkcjonalności do klas w sposób dynamiczny, podczas działania programu.
Przykładem wzorca może być dekoracja wnętrza mieszkania. Dodanie do pomieszczeń dywanów, szafek lub kwiatów doniczkowych (konkretnych dekoratorów) nie wpłynie na zmianę konstrukcji budynku, ścian nośnych itp. Komponentem, w tym przypadku może być obiekt budynku.
SCHEMAT WZORCA DEKORATOR
Źródło: pl.wikipedia.org/wiki/Dekorator_(wzorzec_projektowy)
Z diagramu wynika, że Dekorator dodaje KonkretneDekoratory (A, B, …) do komponentu i rozbudowuje jego strukturę (dekoruje go poprzez +dodaneZachowanie()). Interfejs Dekorator dziedziczy po interfejsie Komponent. Wszyscy uczestnicy wzorca korzystają ze wspólnego interfejsu – Komponent.
PRZYKŁAD
Do obrazka na stronie internetowej dodamy nową funkcjonalność: możliwość zamieszczenia krótkiego podpisu pod nim.

Domyślny stan, np:
1 |
<img src="file.jpg" alt="example"> |
Po użyciu wzorca postać znacznika img będzie wzbogacona o tagi: figure i figcaption:
1 2 3 4 |
<figure> <img src="file.jpg" alt="example"> <figcaption> caption </figcaption> </figure> |
Najpierw tworzymy abstrakcyjny komponent Image, bo o nim mowa 🙂 . Do klasy dodajemy również abstrakcyjną funkcją getImage($src, $alt), która pobiera dwa parametry: $src – adres do pliku oraz $alt – alternatywny tekst na obrazku:
1 2 3 4 5 6 7 8 9 10 11 |
<?php // Image.php // Komponent abstract class Image { abstract public function getImage($src, $alt); } ?> |
Tworzymy konkretny komponent – DefaultImage, który dziedziczy po klasie Image funkcję getImage, dodając do niej implementację. Właściwości $src i $alt są ustawiane w kodzie html obrazka: <img src=”$src” alt=”$alt” />
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php // DefaultImage.php // Konkretny komponent class DefaultImage extends Image { private $src; private $alt; public function getImage($src, $alt) { $this->src = $src; $this->alt = $alt; echo '<img src="'.$this->src.'" alt="'.$this->alt.'">'; } } ?> |
W tym momencie klasa DefaultImage jest już użyteczna i możemy z niej korzystać. Załóżmy jednak, że będzie nam potrzebna jeszcze wersja z podpisem, w tym celu użyjemy właśnie dekoratora 🙂
Klasa dekoratora – Decorator zawiera tylko jedną właściwość – $caption, której użyjemy do ustawienia podpisu pod obrazkiem:
1 2 3 4 5 6 7 8 9 10 11 |
<?php // Decorator.php // Dekorator abstract class Decorator extends Image { protected $caption; } ?> |
Głównym zadaniem dekoratora jest oczywiście zachowanie referencji do komponentu Image. Co ciekawe, klasa dekoratora jest abstrakcyjna i dziedziczy również po abstrakcyjnej klasie Image.
Kolejna klasa, którą musimy dodać (zgodnie z diagramem wzorca) to „konkretny dekorator” – ImageCaption. Klasa ta dziedziczy po klasie Decorator i jest głównym uczestnikiem dekoracji 🙂 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php // ImageCaption.php // Konkretny dekorator class ImageCaption extends Decorator { private $object; public function __construct(Image $object) { $this->object = $object; } public function setCaption($caption) { $this->caption = $caption; } public function getImage($src, $alt) { echo '<figure>'; echo $this->object->getImage($src, $alt); echo '<figcaption>'.$this->caption.'</figcaption>'; echo '</figure>'; } } ?> |
Do konstruktora przekazujemy (poprzez typowanie) obiekt Image i ustawiamy referencję do niego. Metoda setCaption ustawia podpis, który zostaje wstrzyknięty do głównej metody getImage, wyświetlającej obrazek na stronie.
Na koniec tworzymy klasę klienta, która wyświetli żądania:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php // Client.php // Klient spl_autoload_register(function ($class_name) { include $class_name . '.php'; }); $img = new DefaultImage(); $decorator = new ImageCaption($img); $src = 'https://geekster.pl/wp-content/uploads/2019/07/dekorator.jpg'; $alt = 'Decorator'; $decorator->setCaption('Caption :)'); $decorator->getImage($src, $alt); ?> |
Wpierw tworzymy instancję „konkretnego komponentu”:
$img = new DefaultImage()
a następnie wstrzykujemy ją do „konkretnego dekoratora”:
$decorator = new ImageCaption($img)
Reszta to już pikuś 😉 Metoda setCaption ustawia podpis pod obrazkiem. Natomiast getImage($src, $alt) ustawia adres do pliku i tekst alternatywny (gdyby coś poszło nie tak) oraz wyświetla efekt końcowy na stronie.