Wzorzec dekoratora
Z Wikipedii
Wzorzec dekoratora to w inżynierii oprogramowania jeden ze wzorców projektowych należący do grupy wzorców strukturalnych. Pozwala na dodanie nowej funkcjonalności do istniejących klas 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ą funkcjonalność.
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.
Ponieważ w większości obiektowych języków programowania nie można tworzyć nowych klas podczas działania programu i zwykle nie można przewidzieć z góry wszystkich kombinacji rozszerzeń klas, konieczne by było stworzenie nowej klasy dla każdej kombinacji. Dekoratory są obiektami, tworzonymi w czasie działania programu, i mogą być łączone w różne kombinacje bezpośrednio przy użyciu. Przykładem wzorca dekoratora jest implementacja strumieni I/O w Javie.
[edytuj] Cel
Rozważmy okno w graficznym interfejsie użytkownika. By pozwolić na przewijanie jego zawartości, chcemy dodać do niego poziome i/lub pionowe paski przewijania. Załóżmy, że okna są reprezentowane przez instancje klasy Okno i że ta klasa nie ma żadnych metod dodających paski przewijania. Moglibyśmy stworzyć podklasę PrzewijaneOkno, która udostępniałaby te metody lub stworzyć OknoDekoratorPrzewijane, który jedynie dodawałby tą funkcjonalność do istniejących obiektów Okno. W tym miejscu działałyby oba rozwiązania.
Teraz załóżmy, że potrzeba dodać ramki dookoła okien. I w tym przypadku klasa Okno nie ma takiej funkcjonalności. Jest teraz problem z podklasą OknoPrzewijane, bo by dodać ramki do wszystkich okien potrzeba stworzyć podklasy OknoZRamką i OknoPrzewijaneZRamką. Problem staje się jeszcze większy z każdą kolejną opcją. W przypadku dekoratorów wystarczy stworzyć jedną klasę OknoDekoratorRamka - podczas działania programu można dynamicznie dekorować istniejące okna z OknoDekoratorPrzewijane lub OknoDekoratorRamka lub oboma.
[edytuj] Przykład
Kod w Java:
// interfejs Okno interface Okno { public void rysuj(); // rysuje Okno na ekranie public String pobierzOpis(); // zwraca opis Okna } // 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"; } }
Poniższe klasy zawierają dekoratory dla wszystkich klas Okno, w tym też dla klas dekoratorów.
// abstrakcyjna klasa dekorator - implementuje interfejs Okno abstract class OknoDekorator implements Okno { protected Okno dekorowaneOkno; // dekorowane Okno public OknoDekorator(Okno dekorowaneOkno) { this.dekorowaneOkno = dekorowaneOkno; } } // pierwszy dekorator dodający pionowe paski przewijania class PionowePrzewijanieDekorator extends OknoDekorator { public PionowePrzewijanieDekorator (Okno dekorowaneOkno) { super(dekorowaneOkno); } public void draw() { rysujPionowyPasekPrzewijania(); dekorowaneOkno.draw(); } private void rysujPionowyPasekPrzewijania() { // rysuj pionowy pasek przewijania } public String pobierzOpis() { return dekorowaneOkno.pobierzOpis() + ", z pionowym paskiem przewijania"; } } // drugi dekorator dodający poziome paski przewijania class PoziomePrzewijanieDekorator extends OknoDekorator { public PoziomePrzewijanieDekorator (Okno dekorowaneOkno) { super(dekorowaneOkno); } public void draw() { rysujPoziomyPasekPrzewijania(); dekorowaneOkno.draw(); } private void rysujPoziomyPasekPrzewijania() { // rysuj poziomy pasek przewijania } public String pobierzOpis() { return dekorowaneOkno.pobierzOpis() + ", z poziomym paskiem przewijania"; } }
Program testowy, który tworzy obiekt klasy Okno, dekoruje go poziomymi i pionowymi paskami przewijania i wypisuje jego opis.
public class DekorowaneOknoTest { public static void main(String[] args) { // utwórz dekorowane Okno z poziomymi i pionowymi paskami przewijania Window dekorowaneOkno = new PoziomePrzewijanieDekorator( new PionowePrzewijanieDekorator(new ZwykłeOkno())); // wypisz opis Okna System.out.println(dekorowaneOkno.pobierzOpis()); } }
Program wypisuje "zwykłe okno, z pionowym paskiem przewijania, z poziomym paskiem przewijania".