JavaRush /Blog Java /Random-PL /Wzór dekoratora Java

Wzór dekoratora Java

Opublikowano w grupie Random-PL
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
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION