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

php oop wzorzec 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.

dekorator  

Podpis pod obrazkiem

Domyślny stan, np:

Po użyciu wzorca postać znacznika img będzie wzbogacona o tagi: figure i figcaption:

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:

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” />

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:

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 🙂 :

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:

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.

Przykład na GitHub →