Wzorce programistyczne – Dekorator (Decorator) w C++ i PHP

Wzorzec programistyczny typu Dekorator jest bardzo wygodnym sposobem wzbogacania (dekorowania) obiektu w czasie rzeczywistym. Efekt ten jest osiągany poprzez wrappowanie instancji obiektu w kolejne instancje, które dodają do obiektu bazowego kolejne funkcjonalności.

Wzorzec opiszę na 2 przykładach. Pierwszy będzie to przykład oparty o PHP i zaczerpnięty z frameworków do tworzenia stron WWW. Będziemy chcieli osiągnąć efekt wrapowania tagów HTML w kolejne tagi. Dla przykładu:

$box1 = new Div(new Link( new Image() ));
$box1->printOut();

Powyższy kod ma dać w efekcie wydruk na ekranie w postaci:

<div><a><img/></a></div>

Zaczniemy od interface’u o nazwie iPrintable, który będzie enkapsulować przykładową funkcjonalność związaną z tagiem, czyli drukowanie na ekranie.

interface Printable
{
  public function printOut();
}

Teraz oprogramujemy sobie pierwszą klasę – Image – która będzie reprezentować tag img. Klasa Image nie będzie dekoratorem tylko zwykłą klasą, gdyż tag img nie może zawierać wewnątrz innych tagów.

class Image implements iPrintable {
  public function printOut() {
    echo '<img/>';
  }
}

Teraz napiszemy klasę dekoratora enkapsulującą funkcjonalności związane z linkiem.

class Link implements iPrintable {
  protected $inner;
 
  public function __construct(iPrintable $inner) {
    $this->inner = $inner;
  }
 
  public function printOut() {
    echo '<a>';
    $this->inner->printOut();
    echo '</a>';
  }
}

Teraz napiszemy drugą klasę dekoratora enkapsulującą funkcjonalności związane z div’em.

class Div implements iPrintable {
  protected $inner;
 
  public function __construct(iPrintable $inner) {
    $this->inner = $inner;
  }
 
  public function printOut() {
    echo '<div>';
    $this->inner->printOut();
    echo '</div>';
  }
}

Oczywiście, wzorzec Dekoratora nie musi mieć nic wspólnego z pokazanym powyżej wrappowaniem tagów. Poniższy przykład w C++ pokaże inne przykładowe zastosowanie tego wzorca.

class Value
{
  public: 
    int value;
 
    Value() {
        value = 5;
    }
};
 
//----------------------------------------------
 
class ValueDecorator
{
  protected:
    Value* inner;
 
  public:        
    ValueDecorator(Value* inner) {
        this->inner = inner;
    }
 
    void printOut() {
        cout << inner->value + 1;
    }
};
 
//----------------------------------------------
 
int main()
{
    ValueDecorator d( new Value );
    d.printOut();
}

Jak widać na powyższym przykładzie, klasa Dekoratora dodaje liczbę 1 do wartości bazowej wziętej z klasy, którą dekoruje.