Dekorátor

Dekorátor je jeden ze strukturálních návrhových vzorů, které řeší otázku struktury programu. Je znám také pod názvem Wrapper.

Charakteristika

[editovat | editovat zdroj]

Dekorátor se vytváří za účelem změny instancí tříd bez nutnosti vytvoření nových odvozených tříd, jelikož pouze dynamicky připojuje další funkčnosti k objektu. Každá dodaná funkčnost je u dekorátoru implementována jako „ozdobení“ (dekorování) jiného objektu. Dekorátor tedy rozšiřuje objekt, ne třídu, jak je tomu u statické dědičnosti.

Dekorátor je vhodný v následujících případech

[editovat | editovat zdroj]
  • Dynamicky přidáváme povinnosti jednotlivým objektům (bez ovlivnění jiných objektů)
    • Povinnosti lze případně i odebrat
  • Pokud rozšiřování pomocí podtříd není praktické. Kupříkladu máme třídu pro tlačítko, kterou používáme pro 50 tlačítek a pro 10 tlačítek nyní potřebujeme nadefinovat trochu odlišnou funkčnost (např. okraj tlačítka). V případě použití podtříd nám vznikne 10 odvozených tříd a výsledný kód se může stát nepřehledným.
  • Třídní definice může být skrytá či jinak nedostupná pro tvorbu podtříd.

Implementace

[editovat | editovat zdroj]
UML diagram návrhového vzoru dekorátor (zmrzlina)

Problematika dekorátoru bude uvedena na velmi jednoduchém příkladu, aby došlo k rychlému osvojení. Je zapotřebí vytvořit zmrzlinu a k ní několik odlišných polev, které zmrzlinu ozdobí. Pokud bude použit návrhový vzor dekorátor, je zapotřebí si nadefinovat základní zmrzlinu a poté si nadefinovat polevy, kterými bude zmrzlina ozdobena, viz obrázek - UML diagram. Příklad je uveden v jazyce Java, ale k pochopení základního principu postačí znalost kteréhokoliv objektově orientovaného jazyka.

Interface, který bude znázorňovat zmrzlinu
public interface Icecream {
   public String makeIcecream();
}
Základní třída, na kterou budou dekorátory (tedy polevy) přidány, má tuto podobu
public class SimpleIcecream implements Icecream { 
 @Override
 public String makeIcecream() {
   return "Base Icecream";
 }
}
Následující třída tvoří jádro dekorátoru. Instance budou konstruktorem dynamicky dosazovány při tvorbě dekorátoru a po dosazení se zavolá metoda instance
abstract class IcecreamDecorator implements Icecream {

 protected Icecream specialIcecream;

 public IcecreamDecorator(Icecream specialIcecream) {
   this.specialIcecream = specialIcecream;
 }

 public String makeIcecream() {
   return specialIcecream.makeIcecream();
 }
}
Nyní už je zapotřebí pouze samotných dekorátorů. Dekorátor je v tomto případě třída, která implementuje abstraktní dekorátor, viz předešlý krok. Jakmile je dekorátor vytvořen, je základní instance za použití konstruktoru přiřazena do nadřazené třídy. Metoda „makeIcecream“ volá základní metodu následovanou vlastní metodou „addHoney()“, která rozšiřuje funkčnost o vlastní kroky
public class HoneyDecorator extends IcecreamDecorator {

 public HoneyDecorator(Icecream specialIcecream) {
   super(specialIcecream);
 }

 public String makeIcecream() {
   return specialIcecream.makeIcecream() + addHoney();
 }
 
 private String addHoney() {
   return " + sweet honey";
 }
}
Další dekorátory jsou tvorbou shodné
public class NuttyDecorator extends IcecreamDecorator {

 public NuttyDecorator(Icecream specialIcecream) {
   super(specialIcecream);
 }

 public String makeIcecream() {
   return specialIcecream.makeIcecream() + addNuts();
 }

 private String addNuts() {
   return " + crunchy nuts";
 }
}

Použití dekorátoru

[editovat | editovat zdroj]

Nyní lze použít kterékoliv dekorátory v kterémkoliv pořadí. Tato flexibilita a proměnlivost chování instance za běhu, jak si zvolíme, je základní výhoda návrhového vzoru dekorátor

public class TestDecorator {

 public static void main(String args[]) {
   Icecream icecream = new HoneyDecorator(new NuttyDecorator(new SimpleIcecream()));
   System.out.println(icecream.makeIcecream());
 } 
}

Předešlá testovací třída vytvoří takovýto výstup

 "Base Icecream + crunchy nuts + sweet honey"

Dekorátor je velmi podobný adaptéru, ale nepřekrývá původní protokol ošetřovaného objektu. Dekorátor je v určitých případech také vhodnější než obyčejné dědění, jelikož při vytvoření nové funkčnosti by v případě klasické dědičnosti zdědily tuto funkčnost všechny objekty a to znamená, že i ty, které by funkčnost vůbec nepotřebovaly. To se u dekorátoru nestane.

Literatura

[editovat | editovat zdroj]
  • PECINOVSKÝ, Rudolf. Návrhové vzory. 1. Vydání. Praha: CPress, 2007. 528 s. EAN 9788025115824.
  • GAMMA E. - HELM R. - JOHNSON R. - VLISSIDES J. Návrh programů pomocí vzorů: Stavební kameny objektově orientovaných programů. 1. Vydání. Praha: Grada, 2003 ISBN 80-247-0302-5.

Externí odkazy

[editovat | editovat zdroj]