
08 Wrz Wzorce projektowe – Dekorator
Przyszedł czas na kolejny wzorzec projektowy. Wcześniej opisywałam już Strategię i Metodę wytwórczą, czyli odpowiednio wzorzec czynnościowy i kreacyjny. Dzisiaj pierwszy przykład z grupy wzorców strukturalnych. Będzie nim Dekorator.
Na czym polega dekorator?
Dekorator jak już wspomniałam, należy do grupy wzorców strukturalnych. Wykorzystujemy go, aby stworzyć jak najbardziej elastyczną architekturę aplikacji. Bo w końcu, po co nam sztywna aplikacja, którą jest ciężko rozbudowywać.
Wzorzec ten rozbudowuje strukturę bez ingerencji w istniejące obiekty. Jest pomocny w sytuacji, gdy potrzebujemy dynamicznie rozszerzyć obiekt o jakąś funkcjonalność lub zmienić istaniejącą. Co to znaczy dynamicznie? To oznacza, że nie chcemy, aby każdy obiekt danej klasy miał tę funkcjonalność, tylko aby w konkretnych warunkach obiekt był o nią poszerzony. Wiem, trochę zagmatwane, ale postaram się to dokładniej wytłumaczyć w dalszej części tekstu.
Model
To jeden z nielicznych wzorców, który zaleca dziedziczenie klasy abstrakcyjnej po klasie abstrakcyjnej. Jest bardzo podobny do Adaptera. Opakowuje komponent, czyli klasę, którą chcemy rozszerzyć.

Równie dobrze, zamiast klas abstrakcyjnych możemy zastosować interfejsy, też będzie to dobre rozwiązanie. Możemy zmieszać te dwie metody, czyli np. AbstractComponent będzie interfejsem Component a AbstractDecorator będzie klasą abstrakcyjną. To zależy od kontekstu zastosowania. Możemy go sobie dostosować do naszych potrzeb.
Zastosowanie
- Dekorator stosujemy w sytuacji, gdy nie do każdego obiektu danej klasy chcemy dodać jakąś funkcjonalność.
- Kiedy nie chcemy lub nie możemy zmienić struktury obiektów a potrzebujemy dokonać pewnych zmian w działaniu funkcji, lub rozszerzyć obiekt.
- Jeśli opcji rozszerzenia obiektu jest na tyle dużo, że tworzenie osobnej klasy dla każdej z nich byłoby niepraktyczne, biorąc pod uwagę ilość kombinacji.
Przykład
Poniższy przykład przedstawia Dekorator z użyciem podwójnej klasy abstrakcyjnej. W tym wypadku rozszerzamy istniejące już w obiekcie funkcje o dodatkowe rzeczy jak dodanie wykrzyknika do tytułu czy escape znaków specjalnych w treści.
<?php
abstract class AbstractComponent {
protected $title;
protected $content;
abstract function getTitle();
abstract function getContent();
}
class Article extends AbstractComponent {
function __construct($title, $content) {
$this->title = $title;
$this->content = $content;
}
function getContent() {
return $this->content;
}
function getTitle() {
return $this->title;
}
}
abstract class Decorator extends AbstractComponent {
protected $article;
}
class TitleDecorator extends Decorator {
public function __construct(Article $article) {
$this->article = $article;
}
function getTitle() {
return $this->article->title . "!";
}
function getTitle() {
return $this->title;
}
}
class ContentDecorator extends Decorator {
public function __construct(Article $article) {
$this->article = $article;
}
function getTitle() {
return $this->title;
}
function getContent() {
return htmlspecialchars($this->article->title);
}
}
$article = new Article('Tytuł', '<p>Treść</p>');
$article = new TitleDecorator($article);
$article = new ContentDecorator($article);
echo $article->getTitle() . ' ' . $article->getContent();
?>
Kolejny przykład to zastosowanie dekoratora z użyciem interfejsu i klasy abstrakcyjnej. W tym przypadku nie rozszerzamy istniejących funkcji, a dodajemy nowe.
<?php
interface Component {
function getTitle();
function getContent();
}
class Article implements Component {
private $content;
private $title;
function __construct($title, $content) {
$this->content = $content;
$this->title = $title;
}
function getContent() {
return $this->content;
}
function getTitle() {
return $this->title;
}
}
abstract class Decorator implements Component {
protected $article;
public function __construct(Article $article) {
$this->article = $article;
}
}
class TitleDecorator extends Decorator {
function exclaimTitle() {
return $this->article->title . "!";
}
function getTitle() {
return $this->article->title;
}
function getContent() {
return $this->article->content;
}
}
class ContentDecorator extends Decorator {
function escapeContent() {
return htmlspecialchars($this->article->title);
}
function getTitle() {
return $this->article->title;
}
function getContent() {
return $this->article->content;
}
}
$article = new Article('Tytuł', '<p>Treść</p>');
$titleDecorator = new TitleDecorator($article);
$contentDecorator = new BookTitleStarDecorator($article);
echo $titleDecorator->exclaimTitle();
echo $contentDecorator->escapeContent();
?>
Infografika
