Wzór projektowy dekoratora
Mogę postawić siebie na pierwszym miejscu, nawet jeśli chcę
Mamy interfejs o nazwie Płatność zawiera metodę płatności .
I konkretna klasa DefaultPayment do wdrożenia metody, metoda przyjmuje cenę jako argument do wykonania logiki płatności.
public interface Payment {
void pay(BigDecimal price);
}
public class DefaultPayment implements Payment {
@Override
public void pay(BigDecimal price) {
System.out.println("Payed: " + price);
}
}
public class Client {
public static void main(String[] args) {
Payment defaultPayment = new DefaultPayment();
defaultPayment.pay(BigDecimal.valueOf(100));
}
}
Załóżmy, że jest podatek od produktu, za który chcę zapłacić, co mogę zrobić?
Możemy skorzystać z naszego projektu, który zaprojektowaliśmy dla interfejsu, a nie dla implementacji.
Możemy więc stworzyć klasę dla Payment i pozwolić jej być typem Payment , a jednocześnie zachować Payment jako właściwość, która mogłaby pobierać płatność za pomocą swojego konstruktora, a my nazwiemy tę klasę TaxPaymentDecorator .
public class TaxPaymentDecorator implements Payment {
private Payment payment;
private BigDecimal tax = BigDecimal.ZERO;
public TaxPaymentDecorator(Payment payment) {
this.payment = payment;
}
@Override
public void pay(BigDecimal price) {
price = price.add(this.tax);
payment.pay(price);
}
public BigDecimal getTax() {
return tax;
}
public void setTax(BigDecimal tax) {
this.tax = tax;
}
}
A klient może użyć TaxPaymentDecorator w następujący sposób:
public class Client {
public static void main(String[] args) {
TaxPaymentDecorator taxPaymentDecorator = new TaxPaymentDecorator(new DefaultPayment());
taxPaymentDecorator.setTax(BigDecimal.valueOf(50));
taxPaymentDecorator.pay(BigDecimal.valueOf(100));
}
}
public class DiscountPaymentDecorator implements Payment {
private Payment payment;
private BigDecimal discount = BigDecimal.ZERO;
public DiscountPaymentDecorator(Payment payment) {
this.payment = payment;
}
@Override
public void pay(BigDecimal price) {
price = price.subtract(discount);
payment.pay(price);
}
public BigDecimal getDiscount() {
return discount;
}
public void setDiscount(BigDecimal discount) {
this.discount = discount;
}
}
public class Client {
public static void main(String[] args) {
TaxPaymentDecorator taxPaymentDecorator = new TaxPaymentDecorator(new DefaultPayment());
taxPaymentDecorator.setTax(BigDecimal.valueOf(50));
DiscountPaymentDecorator discountPaymentDecorator = new DiscountPaymentDecorator(taxPaymentDecorator);
discountPaymentDecorator.setDiscount(BigDecimal.valueOf(10));
discountPaymentDecorator.pay(BigDecimal.valueOf(100));
}
}
Diagram UML-a
Zasady projektowania
Omówię tutaj trzy zasady projektowania:
- Zaprojektuj interfejs, a nie implementację: jak widzisz, użycie interfejsu Płatności pomogło nam wykorzystać moc OOP poprzez dynamiczne dodawanie zachowania w czasie wykonywania bez żadnych modyfikacji starej implementacji.
- Otwórz swój projekt na rozszerzenie, zamknij na modyfikację: Ten punkt jest powiązany z poprzednim, nasza stara implementacja nie zmuszała nas do żadnych modyfikacji, ale rozszerzyliśmy starą implementację, aby dodać nowe zachowania, i mam na myśli tutaj użycie interfejsu projektu do realizacji.
- Wolisz kompozycję niż dziedziczenie: dekorator używa tutaj kompozycji zamiast próbować używać dziedziczenia, generalnie użycie dziedziczenia może powodować problemy przez zwiększenie sprzężenia i moglibyśmy omówić to w osobnym blogu.
Dynamicznie dołączaj dodatkowe obowiązki do obiektu. Dekoratory zapewniają elastyczną alternatywę dla podklas w celu rozszerzenia funkcjonalności.
W naszym przykładzie dynamicznie połączyliśmy dwa obowiązki w czasie wykonywania, dodaliśmy podatek do ceny i odjęliśmy rabat od ceny, nie zrobiliśmy podklasy dla DefaultPayment, wykorzystaliśmy moc OOP do dodania naszych zachowań w elastyczny sposób, i to jest Wzorzec Dekoratora .

![Czym w ogóle jest lista połączona? [Część 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































