Jedným z najdôležitejších princípov pri vývoji softvéru je princíp otvoreného a uzavretého dizajnu. Tento princíp návrhu zdôrazňuje, že triedy by mali byť otvorené pre rozšírenie, ale uzavreté pre úpravy. Dizajnový vzor dekoratéra stelesňuje princíp otvoreného-uzavretého dizajnu.
Pomocou vzoru dekorátora môžete triedu jednoducho rozšíriť tým, že jej dáte nové správanie bez toho, aby ste zmenili jej existujúci kód. Vzor dekorátora to robí dynamicky za behu pomocou kompozície. Tento návrhový vzor je známy ako flexibilná alternatíva k použitiu dedičnosti na rozšírenie správania.
Ako funguje návrhový vzor dekoratérov?
Hoci dekoračný vzor je alternatívou k triedne dedičstvo, do svojho dizajnu zahŕňa niektoré aspekty dedenia. Kľúčovým aspektom dekoračného vzoru je, že všetky jeho triedy spolu súvisia, či už priamo alebo nepriamo.
Typický dizajnový vzor dekoratérov má nasledujúcu štruktúru:
Z vyššie uvedeného diagramu tried môžete vidieť, že vzor dekoratérov má štyri hlavné triedy.
Komponent: toto je abstraktná trieda (alebo rozhranie), ktorá slúži ako nadtyp pre dekoračný vzor.
Betónový komponent: toto sú objekty, ktoré môžete za behu ozdobiť rôznymi spôsobmi správania. Dedí z rozhrania komponentu a implementujú jeho abstraktné funkcie.
Dekoratér: táto trieda je abstraktná a má rovnaký supertyp ako objekt, ktorý bude zdobiť. V diagrame tried uvidíte dva vzťahy medzi triedami komponentov a dekorátorov. Prvý vzťah je vzťahom dedenia; každý dekoratér je a komponent. Druhým vzťahom je zloženie; každý dekoratér má (alebo obaľuje a) komponent.
Dekoratér betónu: toto sú jednotlivé dekorátory, ktoré dodávajú komponentu špecifické správanie. Mali by ste si uvedomiť, že každý dekorátor betónu má premennú inštancie, ktorá obsahuje odkaz na komponent.
Implementácia vzoru Decorator Design Pattern v jazyku Java
Vzorová aplikácia na objednávanie pizze môže adekvátne demonštrovať, ako použiť vzor dekorátora na vývoj aplikácií. Táto vzorová aplikácia na pizzu umožňuje zákazníkom objednať si pizzu s viacerými polevami. Prvou triedou dekoračného vzoru je rozhranie pizze:
verejnostirozhraniePizza{
verejnostiabstraktné Reťazec popis();
verejnostiabstraktnédvojitýnáklady();
}
Rozhranie Pizza je trieda komponentov. Takže z neho môžete vytvoriť jednu alebo viac konkrétnych tried. Spoločnosť vyrábajúca pizzu vyrába dva hlavné typy pízz na základe ich cesta. Jeden druh pizze má kysnuté cesto:
verejnostitriedaDroždieCrustPizzanáradiaPizza{
@Prepísať
verejnosti Reťazec popis(){
vrátiť"Pizzové cesto s droždím";
}
@Prepísať
verejnostidvojitýnáklady(){
vrátiť18.00;
}
}
YeastCrustPizza je prvý betón triedy Java rozhrania Pizza. Ďalším dostupným typom pizze je plochý chlieb:
verejnostitriedaFlatbreadCrustPizzanáradiaPizza{
@Prepísať
verejnosti Reťazec popis(){
vrátiť"Cesto na pizzu s chlebom";
}
@Prepísať
verejnostidvojitýnáklady(){
vrátiť15.00;
}
}
Trieda FlatbreadCrustPizza je druhým konkrétnym komponentom a podobne ako trieda YeastCrustPizza implementuje všetky abstraktné funkcie rozhrania Pizza.
Dekoratéri
Trieda dekorátora je vždy abstraktná, takže z nej nemôžete vytvoriť novú inštanciu. Je však potrebné vytvoriť vzťah medzi rôznymi dekoratérmi a komponentmi, ktoré budú zdobiť.
verejnostiabstraktnétriedaToppingDecoratornáradiaPizza{
verejnosti Reťazec popis(){
vrátiť"Neznámy topping";
}
}
Trieda ToppingDecorator predstavuje triedu dekoratérov v tejto vzorovej aplikácii. Teraz môže spoločnosť vyrábajúca pizzu vytvárať mnoho rôznych polevy (alebo dekoratérov) pomocou triedy ToppingDecorator. Povedzme, že pizza môže mať tri rôzne druhy polevy, a to syr, feferónky a huby.
Syrová poleva
verejnostitriedaSyrpredlžujeToppingDecorator{
súkromné Pizza pizza;verejnostiSyr(Pizza){
toto.pizza = pizza;
}@Prepísať
verejnosti Reťazec popis(){
vrátiť pizza.popis() + "Syrová poleva";
}
@Prepísať
verejnostidvojitýnáklady(){
vrátiťpizza.náklady() + 2.50;
}
}
Poleva na papriky
verejnostitriedaPepperonipredlžujeToppingDecorator{
súkromné Pizza pizza;verejnostiPepperoni(Pizza){
toto.pizza = pizza;
}@Prepísať
verejnosti Reťazec popis(){
vrátiť pizza.popis() + "Papriková poleva";
}
@Prepísať
verejnostidvojitýnáklady(){
vrátiťpizza.náklady() + 3.50;
}
}
Hubová poleva
verejnostitriedaHubapredlžujeToppingDecorator{
súkromné Pizza pizza;verejnostiHuba(Pizza){
toto.pizza = pizza;
}
@Prepísať
verejnosti Reťazec popis(){
vrátiť pizza.popis() + "Hubová poleva";
}
@Prepísať
verejnostidvojitýnáklady(){
vrátiťpizza.náklady() + 4.50;
}
}
Teraz máte jednoduchú aplikáciu implementovanú pomocou vzoru dekorátora. Ak by si zákazník objednal pizzu s droždím so syrom a feferónkami, testovací kód pre tento scenár bude vyzerať takto:
verejnostitriedaHlavná{
verejnostistatickéneplatnéHlavná(Reťazec[] argumentov){
Pizza pizza1 = Nový DroždieCrustPizza();
pizza1 = Nový Pepperoni (pizza1);
pizza1 = Nový Syr (pizza1);
System.out.println (pizza1.description() + " $" + pizza1.cena());
}
}
Spustenie tohto kódu vytvorí v konzole nasledujúci výstup:
Ako vidíte, výstup uvádza typ pizze spolu s jej celkovou cenou. Pizza začínala ako pizza s droždím za 18,00 dolárov, ale so vzorom dekoratérov bola aplikácia schopná pridať pizze nové funkcie a ich primeranú cenu. Takto dáva pizze nové správanie bez toho, aby sa zmenil existujúci kód (pizza s droždím).
S dekoračným vzorom môžete tiež aplikovať rovnaké správanie na objekt toľkokrát, koľkokrát chcete. Ak si zákazník objedná pizzu so všetkým, čo je na nej, a nejakým extra syrom, môžete aktualizovať hlavnú triedu nasledujúcim kódom, aby to odrážal:
Pizza pizza2 = Nový DroždieCrustPizza();
pizza2 = Nový Pepperoni (pizza2);
pizza2 = Nový Syr (pizza2);
pizza2 = Nový Syr (pizza2);
pizza2 = Nový Huby (pizza2);System.out.println (pizza2.description() + " $" + pizza2.cost());
Aktualizovaná aplikácia vytvorí v konzole nasledujúci výstup:
Výhody použitia vzoru dekorátora
Dve hlavné výhody použitia dekoračného vzoru sú bezpečnosť a flexibilita. Vzor dekorátora vám umožňuje vyvinúť bezpečnejší kód tým, že nezasahuje do už existujúceho zabezpečeného kódu. Namiesto toho rozširuje existujúci kód prostredníctvom zloženia. Efektívne predchádzanie zavedeniu nových chýb alebo neúmyselných vedľajších účinkov.
Vďaka zloženiu má vývojka tiež veľkú flexibilitu pri použití dekoračného vzoru. Kedykoľvek môžete implementovať nový dekorátor a pridať nové správanie bez toho, aby ste zmenili existujúci kód a prerušili aplikáciu.