sobota, 1 marca 2014

Dekorator (obiektowy)

Dekorator (Decorator)


Umożliwia dodanie nowej funkcjonalności dynamicznie podczas działania programu.

Wzorzec dekoratora polega na opakowaniu oryginalnej klasy w nową klasę "dekorującą". Zwykle przekazuje się oryginalny obiekt jako parametr konstruktora dekoratora, metody dekoratora wywołują metody oryginalnego obiektu i dodatkowo implementują nową funkcję.

Dekoratory są alternatywą dla dziedziczenia. Dziedziczenie rozszerza zachowanie klasy w trakcie kompilacji, w przeciwieństwie do dekoratorów, które rozszerzają klasy w czasie działania programu.

Jest to dosyć jasny wzorzec wiec szybko przejde do przykładu.

1. Na początek tworzymy interfejs Okno.
interface Okno {
    public void rysuj(); // rysuje Okno na ekranie
    public String pobierzOpis(); // zwraca opis Okna
}
2. Implementacja zwykłego okna bez pasków przewijania.
class ZwykłeOkno implements Okno {
    public void rysuj() {
        // rysuj okno
    }
 
    public String pobierzOpis() {
        return "zwykłe okno";
    }
}
3. Abstrakcyjna klasa dekorator - implementuje interfejs Okno. Klasa OknoDekorator przechowuje w sobie jako pole Okno. To właśnie okno będzie dekorowane, dlatego więc do konstruktora klasy przekazane zostanie okno, które będzie mialo zostać udekorowane. Jest to klasa abstrakcyjna wiec nie jest wymagane, aby implementowac wszystkie metody z interfejsu Okno.
abstract class OknoDekorator implements Okno {
    protected Okno dekorowaneOkno; // dekorowane Okno
 
    public OknoDekorator(Okno dekorowaneOkno) {
        this.dekorowaneOkno = dekorowaneOkno;
    }
}
4. Czas na pierwszy dekorator dodający pionowe paski przewijania. Każdy dekorator na swój sposób implementuje/dekoruje metode rysuj(). W klasie PionowePrzewijanieDekorator w metodzie rysuj() wywolujemy tez metode rysuj() na rzecz obiektu dekorowaneOkno.
class PionowePrzewijanieDekorator extends OknoDekorator {
    public PionowePrzewijanieDekorator (Okno dekorowaneOkno) {
        super(dekorowaneOkno);
    }
 
    public void rysuj() {
        rysujPionowyPasekPrzewijania();
        dekorowaneOkno.rysuj();
    }
 
    private void rysujPionowyPasekPrzewijania() {
        // rysuj pionowy pasek przewijania
    }
 
    public String pobierzOpis() {
        return dekorowaneOkno.pobierzOpis() + ", z pionowym paskiem przewijania";
    }
}
5. Drugi inny dekorator dodający poziome paski przewijania.
class PoziomePrzewijanieDekorator extends OknoDekorator {
    public PoziomePrzewijanieDekorator (Okno dekorowaneOkno) {
        super(dekorowaneOkno);
    }
 
    public void rysuj() {
        rysujPoziomyPasekPrzewijania();
        dekorowaneOkno.rysuj();
    }
 
    private void rysujPoziomyPasekPrzewijania() {
        // rysuj poziomy pasek przewijania
    }
 
    public String pobierzOpis() {
        return dekorowaneOkno.pobierzOpis() + ", z poziomym paskiem przewijania";
    }
}
6. Na sam koniec program testowy, który tworzy obiekt klasy Okno, dekoruje go poziomymi i pionowymi paskami przewijania i wypisuje jego opis. Prosze zwrócic uwage na sposób w jaki tworzymy dekorowane okno. Najpierw wywolujemy new dla pierwszego dekoratora, nastepnie do konstruktora tego dekoratora przekazujemy new drugiego dekoratora. Wszystko sie zgadza oba dekoratory przyjmuja jako argument do konstruktora obiekt klasy Okno oraz oba dekoratory dziedzicza po klasie OknoDekorator, a ta z koleji implementuje interfejs Okno. Na samo koniec inicjalizacji dekorowanego okna do konstruktora drugiego dekoratora przekazujemy zwykłeOkno. W następnej linijce pobieramy opis. Można dzięki takiemu zabiegowi łatwo sprawdzić czy wszystko się zgadza.
public class DekorowaneOknoTest {
    public static void main(String[] args) {
        // utwórz dekorowane Okno z poziomymi i pionowymi paskami przewijania
        Okno dekorowaneOkno = new PoziomePrzewijanieDekorator(
                new PionowePrzewijanieDekorator(new ZwykłeOkno()));
 
        // wypisz opis Okna
        System.out.println(dekorowaneOkno.pobierzOpis());
    }
}
Dekorator jest jednym z protszych wzorców. Myśle, że powyższy przykład dość dobrze odzwierciedlił zasade działania tego wzroca. Na koniec tradycyjnie diagram klas :


Brak komentarzy:

Prześlij komentarz