Wzorzec decorator należy do wzorców strukturalnych. W praktyce umożliwia dynamiczne dodawanie nowych funkcji do istniejących klas bez ich fizycznej modyfikacji. Dzięki temu można rozszerzyć możliwości klasy bez ingerowania w jej kod pozostawiając jej oryginalną funkcjonalność.

Aby pokazać działanie wzorca decorator posłużę się prostym przykładem. Załóżmy, że mam klasę zapisującą dane do bazy. Nie chcę zmieniać jej kodu i funkcjonalności ale chcę ją rozszerzyć o walidację danych. Mógłbym zastosować dziedziczenie i wykorzystać dziedziczoną metodą do walidacji ale wówczas musiałbym zmodyfikować kod klasy głównej czego bardzo chcę uniknąć a dodatkowo każda zmiana klasy dziedziczącej wymuszałaby zmiany klas dziedziczonych.

Zacznę od stworzenia wspólnego interfejsu dla klasy dekorowanej i dekoratora:

PHP:
  1. interface IDecorator
  2. {
  3.     function save();
  4. }

Następnie stworzę klasę główną (dekorowaną) implementującą interfejs IDecorator, której kodu podczas rozszerzania nie mam zamiaru modyfikować:

PHP:
  1. class Decorable imlements IDecorator
  2. {
  3.     function save()
  4.     {
  5.         // zapis danych do bazy
  6.         // [...]
  7.     }
  8. }

Teraz przyszła kolej na stworzenie klasy dekorującej czyli wzbogacającej klasę główną Decorable o funkcję walidującą dane, która także implementuje interfejs IDecorator:

PHP:
  1. class Decorate implements IDecorator
  2. {
  3.     /**
  4.      * Obiekt klasy dekorowanej
  5.      *
  6.      * @var object
  7.      * @access private
  8.      */
  9.     private $_decorate;
  10.  
  11.     /**
  12.      * Konstruktor klasy
  13.      *
  14.      * @param object $decorable
  15.      */
  16.     function __construct(Decorable $decorable)
  17.     {
  18.         // przypisanie obiektu klasy dekorowanej do zmiennej prywatnej
  19.         $this->_decorable = $decorable
  20.     }
  21.  
  22.     /**
  23.      * Metoda uruchamia walidacje danych
  24.      */
  25.     function save()
  26.     {
  27.         // walidacja danych
  28.         // [...]
  29.  
  30.         // wywolanie oryginalnej metody z klasy dekorowanej
  31.         $this->_decorable->save();
  32.     }
  33. }

Do konstruktora klasy zostaje przekazany obiekt oryginalnej klasy dekorowanej Decorable. Na koniec pozostaje mi stworzenie obiektu klasy dekorowanej Decorable i przekazanie jej klasie dekorującej Decorate:

PHP:
  1. $action = new Decorate(new Decorable());
  2. $action->save();

Po stworzeniu obiektu klasy Decorable wywołuję metodę save(), która po przeprowadzeniu walidacji wywołuje metodę o tej samej nazwie klasy dekorowanej Decorable.

Jak więc widać rozszerzyłem funkcjonalność klasy oryginalnej nie dokonując w niej żadnych istotnych zmian. Podsumowując dekoratory są w pewnym sensie alternatywą dla dziedziczenia. Dziedziczenie rozszerza zachowanie klasy w trakcie kompilacji, w przeciwieństwie do dekoratorów, które rozszerzają klasy w czasie działania programu.

Więcej o wzorcu dekoratora:
http://pl.wikipedia.org/wiki/Wzorzec_dekoratora
http://4programmers.net/PHP/Wzorce_Projektowe#id-Dekorator
http://www.phppatterns.com/docs/design/decorator_pattern
http://www.fluffycat.com/PHP-Design-Patterns/Decorator
http://www.vincehuston.org/dp/decorator.html

Leave a Reply

You must be logged in to post a comment.