Mẫu thiết kế trang trí

Dec 27 2022
Tôi có thể đặt bản thân mình lên hàng đầu, ngay cả sau khi tôi muốn. Chúng tôi có một giao diện có tên là Thanh toán chứa một phương thức thanh toán. Và một lớp cụ thể DefaultPayment để triển khai phương thức, phương thức này lấy giá làm đối số để thực hiện logic thanh toán.

Tôi có thể đặt bản thân mình lên hàng đầu, ngay cả sau nếu tôi muốn

Bạn có thể thêm đường trước hoặc thậm chí thêm sô cô la lên trên sau khi pha xong cốc Nescafe của mình

Chúng tôi có một giao diện được gọi là Thanh toán chứa một phương thức thanh toán .

Và một lớp cụ thể DefaultPayment để triển khai phương thức, phương thức này lấy giá làm đối số để thực hiện logic thanh toán.

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));
    }
}

Giả sử có một khoản thuế đối với một sản phẩm mà tôi muốn thanh toán, tôi có thể làm gì?

Chúng tôi có thể tận dụng thiết kế của mình, chúng tôi thiết kế cho một giao diện không phải để triển khai.

Vì vậy, chúng ta có thể tạo một lớp cho Thanh toán và để nó là một loại Thanh toán , đồng thời giữ Thanh toán làm thuộc tính và nó có thể nhận khoản thanh toán bằng hàm tạo của nó và chúng ta sẽ gọi lớp này là 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;
    }
}

Và khách hàng có thể sử dụng TaxPaymentDecorator như sau:

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));
    }
}

sơ đồ UML

Biểu đồ UML mẫu thiết kế trang trí

Nguyên tắc thiết kế

Tôi sẽ thảo luận về ba nguyên tắc thiết kế ở đây:

  1. Thiết kế giao diện không phải để triển khai: Như bạn thấy, việc sử dụng giao diện Thanh toán đã giúp chúng tôi sử dụng sức mạnh của OOP bằng cách thêm hành vi một cách linh hoạt vào thời gian chạy mà không có bất kỳ sửa đổi nào đối với triển khai cũ.
  2. Làm cho thiết kế của bạn mở để tiện ích mở rộng đóng để sửa đổi: Điểm này có liên quan đến điểm trước đó, cách triển khai cũ của chúng tôi không buộc chúng tôi phải thực hiện bất kỳ sửa đổi nào, nhưng chúng tôi đã mở rộng cách triển khai cũ để thêm các hành vi mới và ý tôi là ở đây sử dụng giao diện thay thế của thiết kế để thực hiện.
  3. Ưu tiên sáng tác hơn kế thừa: người trang trí sử dụng sáng tác ở đây thay vì cố gắng sử dụng tính kế thừa, nói chung việc sử dụng tính kế thừa có thể gây ra sự cố bằng cách tăng khớp nối và chúng ta có thể thảo luận điều đó trong blog riêng.

Đính kèm các trách nhiệm bổ sung cho một đối tượng một cách linh hoạt. Trình trang trí cung cấp một giải pháp thay thế linh hoạt cho phân lớp để mở rộng chức năng.

Trong ví dụ của chúng tôi, chúng tôi đã đính kèm hai trách nhiệm một cách linh hoạt trong thời gian chạy, chúng tôi thêm thuế vào giá và trừ chiết khấu khỏi giá, chúng tôi không phân loại phụ cho Khoản thanh toán mặc định, chúng tôi đã sử dụng sức mạnh của OOP để thêm các hành vi của mình theo cách linh hoạt, và đó là Decorator Pattern .