Návrhový vzor decorator je typickým představitelem zásady užití kompozice před dědičností. Za předpokladu, že chceme přidat další dodatečné chování (vlastnost) nějakému objektu, pak pro tuto vlastnost vytvoříme vlastní objekt, do kterého ten původní zabalíme (odekorujeme jej).
Tento postup je obzvláště výhodný, pokud mohou existovat objekty s libovolnými kombinacemi těchto vlastností, jelikož při použití prosté dědičnosti by došlo ke kombinatorické explozi počtu tříd. Zároveň by bylo velmi obtížné daný kód udržovat, protože by přidání jedné další vlastnosti znamenalo přidání velkého množství nových tříd. Tento návrhový vzor se používá například v programovacím jazyku Java pro vstupní a výstupní proudy, kdy daný proud může být bufferovaný, filtrovaný, s možností push-back (vrátit znak zpět s tím, že ješte nebyl přečten) a tak podobně. Zároveň jsou veškeré kombinace validní a je žádoucí, aby mohl uživatel odekorovat daný stream nějakou dodatečnou vlastností.
Příklad
Představme si, že chceme připravit kávu. Káva může být s mlékem, cukrem, dvěma cukry, rumem atp. Zároveň ji každý pije s trochu jinými přísadami, proto je na místě použití vzoru decorator.
Kód
/** * Demostrace navrhoveho vzoru decorator * @author Pavel Micka */ public class CoffeeDecorator { public static void main(String[] args){ String coffee = new RumCoffee(new MilkCoffee(new SugarCoffee(new SugarCoffee(new Coffee())))).prepareCoffee(); System.out.println(coffee); //tohle bych pit nechtel :-) } } /** * Interface spolecny cele strukture * @author Pavel Micka */ interface CoffeeInterface{ public String prepareCoffee(); } /** * Kafe (dekorovana trida) * @author Pavel Micka */ class Coffee implements CoffeeInterface{ public String prepareCoffee() { return "Kafe"; } } /** * Prida cukr * @author Pavel Micka */ class SugarCoffee implements CoffeeInterface{ private CoffeeInterface coffee; public SugarCoffee(CoffeeInterface coffee) { this.coffee = coffee; } public String prepareCoffee() { return coffee.prepareCoffee() + " - s cukrem "; } } /** * Prida rum * @author Pavel Micka */ class RumCoffee implements CoffeeInterface{ private CoffeeInterface coffee; public RumCoffee(CoffeeInterface coffee) { this.coffee = coffee; } public String prepareCoffee() { return coffee.prepareCoffee() + " - s tuzemakem"; } } /** * Prida mleko * @author Pavel Micka */ class MilkCoffee implements CoffeeInterface{ private CoffeeInterface coffee; public MilkCoffee(CoffeeInterface coffee) { this.coffee = coffee; } public String prepareCoffee() { return coffee.prepareCoffee() + " - s mlekem"; } }