Návrhové vzory Java (design patterns): Decorator

Dnes sa pozrieme na ďalší návrhový vzor Decorator (java design patterns) z kategórie štrukturálnych vzorov (structural patterns). Návrhové vzory v tejto kategórii sa zaoberajú štruktúrou triedy, ako je dedičnosť (inheritance) a kompozícia (composition).

Čo je návrhový vzor Decorator?

Design pattern Decorator je návrhový vzor, ktorý sa používa na dynamické pridávanie (a odstraňovanie) nových zodpovedností alebo funkcií existujúcim objektom bez ovplyvnenia správania iných objektov z rovnakej triedy. Pridávanie novej funkcionality sa nazýva aj ako dekorovanie (zdobenie), z toho vznikol názov tohto návrhového vzoru.

Aký problém návrhový vzor Decorator rieši?

Rieši problém zmeny inštancií tried bez nutnosti vytvorenia ďalších odvodených tried, pretože novú funkcionalitu pripája k objektu dynamicky. Použitie tohto vzoru môže byť oveľa efektívnejšie ako vytváranie podtried, pretože správanie objektu možno rozšíriť bez definovania úplne nového objektu. Používa sa hlavne, keď potrebujeme rozšíriť objekt (Decorator nerozširuje triedu).

Príklad Decorator implementácie v Jave

Teraz si napíšeme program, ktorý demonštruje použitie návrhového vzoru Decorator na vytváranie zdobených zmrzlín s rôznymi extra prísadami.

Rozhranie IZmrzlina definuje metódu vyrobZmrzlinu(), ktorá bude implementovaná rôznymi zmrzlinami.

IZmrzlina.java

package designpatterns;

public interface IZmrzlina {
    public String vyrobZmrzlinu();
}

Trieda Zmrzlina implementuje rozhranie IZmrzlina a poskytuje základnú implementáciu zmrzliny.

Zmrzlina.java

package designpatterns;

public class Zmrzlina implements IZmrzlina {
    @Override
    public String vyrobZmrzlinu() {
        return "Zmrzlina";
    }
}

Abstraktná trieda ZmrzlinaDecorator implementuje rozhranie IZmrzlina a obsahuje referenciu na inštanciu IZmrzlina, ktorá bude zdobená. Táto trieda vracia výsledok metódy vyrobZmrzlinu() zdobenej zmrzliny.

ZmrzlinaDecorator.java

package designpatterns;

abstract class ZmrzlinaDecorator implements IZmrzlina {
    protected IZmrzlina upravenaZmrzlina;

    public ZmrzlinaDecorator(IZmrzlina upravenaZmrzlina) {
        this.upravenaZmrzlina = upravenaZmrzlina;
    }

    @Override
    public String vyrobZmrzlinu() {
        return upravenaZmrzlina.vyrobZmrzlinu();
    }
}

Trieda CokoladaDecorator je konkrétnym dekorátorom, ktorý pridáva čokoládovú polevu k zmrzline. Táto trieda volá metódu vyrobZmrzlinu() nad referenciou na zmrzlinu a poleje ju čokoládovou polevou.

CokoladaDecorator.java

package designpatterns;

public class CokoladaDecorator extends ZmrzlinaDecorator {

        public CokoladaDecorator(IZmrzlina upravenaZmrzlina) {
            super(upravenaZmrzlina);
        }

        public String vyrobZmrzlinu() {
            return upravenaZmrzlina.vyrobZmrzlinu() + pridajCokoladu();
        }

        private String pridajCokoladu() {
            return ", poliata cokoladovou polevou";
        }
}

Trieda ArasidyDecorator je ďalším konkrétnym dekorátorom, ktorý pridáva drvené arašidy k zmrzline. Podobne ako CokoladaDecorator, táto trieda volá metódu vyrobZmrzlinu() nad referenciou na zmrzlinu a posype ju drvenými arašidmi.

ArasidyDecorator.java

package designpatterns;

public class ArasidyDecorator extends ZmrzlinaDecorator {

        public ArasidyDecorator(IZmrzlina upravenaZmrzlina) {
            super(upravenaZmrzlina);
        }

        public String vyrobZmrzlinu() {
            return upravenaZmrzlina.vyrobZmrzlinu() + pridajArasidy();
        }

        private String pridajArasidy() {
            return ", posypana drvenymi arasidami";
        }
}

V metóde main() vytvárame konkrétny objekt zmrzliny s postupnosťou zdobenia. Začíname s pôvodnou zmrzlinou (Zmrzlina), pridávame najskôr čokoládovú polevu (CokoladaDecorator) a potom drvené arašidy (ArasidyDecorator).

Main.java

import designpatterns.*;

public class Main {
    public static void main(String[] args) {
        IZmrzlina zmrzlina = new ArasidyDecorator(new CokoladaDecorator(new Zmrzlina()));
        System.out.println(zmrzlina.vyrobZmrzlinu());
    }
}

Dekorátory možno kombinovať v ľubovoľnom poradí. Táto flexibilita a dynamické menenie správania inštancie za behu programu je základná výhoda návrhového vzoru Decorator.

Dekorátory možno kombinovať v ľubovoľnom poradí. Táto flexibilita a dynamické menenie správania inštancie za behu programu je základná výhoda návrhového vzoru Decorator.
Výstup z príkladu návrhového vzoru Decorator.

Zhrnutie

Návrhový vzor Decorator sa používa v situácii, keď potrebujeme pridávať dynamicky zodpovednosť do rozhrania zabalením pôvodného kódu. Ak by sme použili obyčajné dedenie pre pridanie novej funkcionality, tak by tuto funkcionalitu zdedili všetky objekty, aj tie, ktoré by ju nepotrebovali. Tomuto vieme použitím tohto vzoru zabrániť.

Pripravili sme pre teba súbory so spomínaným príkladom vo forme kódu, ktorý si môžeš spustiť priamo v Jave. Stiahni si kód Java Decorator tu.

Ovládaš programovací jazyk Java? Ak hľadáš prácu ako Java programátor, pozri si naše firemné benefity a reaguj na najnovšie pracovné ponuky.

O autorovi

Jozef Wagner

Java Developer Senior

Viac ako 10 rokov programujem v Jave, momentálne pracujem v msg life Slovakia ako Java programátor senior a pomáham zákazníkom implementovať ich požiadavky do poistného softvéru Life Factory. Vo voľnom čase si rád oddýchnem v lese, prípadne si zahrám nejakú dobrú počítačovú hru.

Daj nám o sebe vedieť