W książce „Najpierw głowa. Wzorce projektowe” Erica Freemana i Elizabeth Robson definiują to w następujący sposób: Wzorzec Dekorator dynamicznie zapewnia nowe możliwości obiektowi i jest alternatywą dla podklas w celu rozszerzenia funkcjonalności. Spróbujmy przyjrzeć się tej definicji bardziej szczegółowo na przykładzie. Załóżmy, że stworzyłeś jeszcze jedną nowoczesną religię i planujesz zapewnić ludziom odpowiednie usługi. Ponieważ współczesne trendy podążają za wegetarianizmem, ekologią, rozwojem człowieka i z jakiegoś powodu ludziom nie wystarczają „tradycyjne” religie (lub w końcu ateizm), to wtedy, idąc za głównym nurtem, tworzy się kolejną religię New Age (rodzaj syntezy z istniejących religie, biorąc od każdego co lubi). Na początku świadczysz następujące usługi: 1. Wróżenie 2. Horoskop Tj. wszystko wygląda tak: Jest interfejs usługi z ceną oczywiście :) i opisem
public interface Service {
public double getPrice();
public String getLabel();
}
I usług
public class Divination implements Service {
private String label;
private double price;
public Divination(String label, double price) {
this.label = label;
this.price = price;
}
public double getPrice() {
return this.price;
}
public String getLabel() {
return this.label;
}
}
public class Horoscope implements Service {
private String label;
private double price;
public Horoscope(String label, double price) {
this.label = label;
this.price = price;
}
public double getPrice() {
return this.price;
}
public String getLabel() {
return this.label;
}
}
Cóż, odpowiednio pojawiły się 2 zamówienia (wróżenie za pomocą kart Tarota i osobisty horoskop od klienta):
public static void main(String[] args) {
double cost;
// Гадание на Таро
Service taro = new Divination("Таро", 1000);
// И персональный гороскоп
Service personalHoroscope = new Horoscope("Персональный гороскоп", 9000);
cost = taro.getPrice() + personalHoroscope.getPrice();
System.out.println(cost);
}
i wynik programu:
10000.0
Wszystko byłoby dobrze, ale są już setki, jeśli nie tysiące takich jak Ty i musimy nadal rozwijać duchowość ludzi, w przeciwnym razie nie będą już zainteresowani. Dlatego jako opcję zaoferowano dodatkowe opcje do dotychczasowych usług. Przykładowo, wybierając usługę wróżenia (Tarot lub fusy z kawy), jako dodatkową opcję można zamówić charakterystykę czakr lub aury (z własnym kosztem za każdą). Jak można to wdrożyć, aby nie wprowadzać zmian w istniejących klasach usług, gdzie wszystko jest już poprawnie skonfigurowane i obliczone. Możesz utworzyć dodatkowe klasy Wróżenie + Czakry lub Wróżenie + Aura do aktualnej Wróżby:
public class Divination implements Service {
// Здесь своя стоимость и другие методы
}
public class DivinationWithChakras implements Service {
// Здесь своя стоимость и другие методы
}
public class DivinationWithAura implements Service {
// Здесь своя стоимость и другие методы
}
lub po prostu użyj podklasy, tj. rozszerzyć klasę nadrzędną na klasę podrzędną
public class DivinationWithAura extends Divination {
public DivinationWithAura(String label, double price) {
super(label, price);
}
// Здесь своя стоимость и другие методы
}
public class DivinationWithChakras extends Divination {
public DivinationWithChakras(String label, double price) {
super(label, price);
}
// Здесь своя стоимость и другие методы
}
Ale wady są od razu widoczne, rozwijając duchowość całego świata, być może będziemy mieli nowe dodatkowe opcje, czyli nowe zajęcia, a jeśli nadal będziemy musieli łączyć obecne, to klasy będą szybko rosły, przynajmniej nie mamy już dość klasy wróżenia z dwiema opcjami razem, a nie osobno:
public class DivinationWithChakrasAndAura implements Service {
// Здесь своя стоимость и другие методы
}
Tutaj możesz wykorzystać bardzo „oszczędny” wzorzec Dekoratora w Javie. W tym celu utworzymy klasę dla dodatkowych opcji, która również będzie implementować usługę, ale także będzie zawierać usługę. I odpowiednio, gdy będziemy musieli złożyć zamówienie na wróżenie i nawet przy 2 opcjach razem, będzie to wyglądało tak: Interfejs jest taki, jaki był od samego początku
public interface Service {
public double getPrice();
public String getLabel();
}
2 klasy usług, takie same jak poprzednio:
public class Divination implements Service {
private String label;
private double price;
public Divination(String label, double price) {
this.label = label;
this.price = price;
}
public double getPrice() {
return this.price;
}
public String getLabel() {
return this.label;
}
}
public class Horoscope implements Service {
private String label;
private double price;
public Horoscope(String label, double price) {
this.label = label;
this.price = price;
}
public double getPrice() {
return this.price;
}
public String getLabel() {
return this.label;
}
}
Dekorator dla dodatkowych opcji
public class OptionDecorator implements Service {
private Service service;
private String label;
private double price;
public OptionDecorator(Service service, String label, double price) {
this.service = service;
this.label = label;
this.price = price;
}
public double getPrice() {
return this.price + service.getPrice();
}
public String getLabel() {
return this.label + service.getLabel();
}
}
I same opcje (na razie 2):
public class Aura extends OptionDecorator {
public Aura(Service service) {
super(service, "Характеристика ауры", 1500);
}
}
public class Chakra extends OptionDecorator {
public Chakra(Service service) {
super(service, "Характеристика чакр", 500);
}
}
Cóż, samo zamówienie
public static void main(String[] args) {
// Гадание на Таро
Service taro = new Divination("Таро", 1000);
Service chakra = new Chakra(taro);
Service aura = new Aura(chakra);
// И общая стоимость
System.out.println(aura.getPrice());
}
3000.0
co daje wynik sumy usługi głównej i 2 opcji dodatkowych. Oznacza to, że nie ma potrzeby stosowania każdego dodatkowego opcję (lub kombinację obu), aby utworzyć nową klasę. Ponadto opcje te można zastosować nie tylko w usłudze wróżenia, ale także w usłudze horoskopu. Dlatego też, gdy w najbliższej przyszłości będziemy musieli wdrożyć następujące dodatkowe opcje: - kompatybilność partnerów awatarów w sieciach społecznościowych - poprawa przepływu środków pieniężnych poprzez zdalny kanał, będziemy musieli napisać tylko 2 dodatkowe klasy:
public class Channeling extends OptionDecorator {
public Channeling(Service service) {
super(service, "Полет в Поле Чудес", 99999);
}
}
public class Avatar extends OptionDecorator {
public Avatar(Service service) {
super(service, "Ваша любовь в соц сетях", 5555);
}
}
i możesz dodać je do dowolnej usługi:
public static void main(String[] args) {
// Гадание на Таро
Service taro = new Divination("Таро", 1000);
Service chakra = new Chakra(taro);
Service aura = new Aura(chakra);
// И общая стоимость
System.out.println(aura.getPrice());
// Гороскоп
Service horoscope = new Horoscope("Персональный гороскоп", 1000);
Service channenling = new Channeling(horoscope);
Service avatar = new Avatar(channenling);
// И общая стоимость
System.out.println(avatar.getPrice());
}
i wynik programu (którego potrzebujemy):
3000.0
106554.0
GO TO FULL VERSION