Danh mục chuỗi ghi chú đọc sách về Mẫu thiết kế
Mẫu Chiến lược (Strategy Pattern)
Mẫu này định nghĩa một tập hợp các thuật toán, đóng gói từng thuật toán vào những lớp riêng biệt và cho phép chúng có thể hoán đổi lẫn nhau. Mẫu giúp thay đổi thuật toán không làm ảnh hưởng đến các thành phần sử dụng thuật toán.
Ứng dụng thực tế:
Khi bán hàng tại cửa hàng, có thể áp dụng nhiều chính sách giảm giá khác nhau như: giá gốc, chiết khấu, hoàn tiền. Việc chuyển đổi giữa các chính sách này được thực hiện thông qua việc tạo ra các đối tượng khác nhau.
Các lớp cơ bản
Lớp trừu tượng xử lý chi phí
/**
* Lớp trừu tượng xử lý chi phí
*/
public abstract class PaymentProcessor {
/**
* Phương thức trừu tượng để tính toán chi phí
* @param originalPrice giá gốc
* @return giá sau khi áp dụng chính sách
*/
public abstract double calculate(double originalPrice);
}
Các lớp cụ thể xử lý chi phí
/**
* Chính sách tính chi phí bình thường
*/
public class NormalPayment extends PaymentProcessor {
@Override
public double calculate(double originalPrice) {
return originalPrice;
}
}
/**
* Chính sách chiết khấu
*/
public class DiscountPayment extends PaymentProcessor {
private double discountRate;
public DiscountPayment(String rate) {
this.discountRate = Double.parseDouble(rate);
}
@Override
public double calculate(double originalPrice) {
return originalPrice * discountRate;
}
}
/**
* Chính sách hoàn tiền
*/
public class RefundPayment extends PaymentProcessor {
private double condition;
private double refundAmount;
public RefundPayment(String condition, String refund) {
this.condition = Double.parseDouble(condition);
this.refundAmount = Double.parseDouble(refund);
}
@Override
public double calculate(double originalPrice) {
double result = originalPrice;
if (originalPrice >= condition) {
int times = (int) Math.floor(originalPrice / condition);
result = originalPrice - times * refundAmount;
}
return result;
}
}
Lớp quản lý chiến lược
/**
* Quản lý chiến lược thanh toán
*/
public class PaymentContext {
private PaymentProcessor processor;
public PaymentContext(PaymentProcessor processor) {
this.processor = processor;
}
public double getResult(String price) {
return processor.calculate(Double.parseDouble(price));
}
}
Đoạn mã gọi thực thi
public class StrategyExample {
public static void main(String[] args) {
double total = 0.0;
// Áp dụng chính sách giá gốc
total = new PaymentContext(new NormalPayment()).getResult("910");
System.out.println("Chính sách giá gốc: " + total);
// Áp dụng chính sách chiết khấu 20%
total = new PaymentContext(new DiscountPayment("0.8")).getResult("910");
System.out.println("Chính sách chiết khấu: " + total);
// Áp dụng chính sách hoàn tiền: 300 giảm 100
total = new PaymentContext(new RefundPayment("300", "100")).getResult("910");
System.out.println("Chính sách hoàn tiền: " + total);
}
}
Kết quả chạy chương trình
Chính sách giá gốc: 910.0
Chính sách chiết khấu: 728.0
Chính sách hoàn tiền: 610.0
Phân tích
- Mẫu chiến lược giúp xác định các thuật toán khác nhau mà không làm ảnh hưởng đến lớp sử dụng chúng.
- Lớp cha
PaymentProcessorđịnh nghĩa các hành vi chung, giúp dễ dàng mở rộng và bảo trì. - Việc tách riêng từng thuật toán giúp đơn giản hóa kiểm thử từng phần tử độc lập.
- Thay vì dùng điều kiện để chọn thuật toán, mẫu chiến lược giúp loại bỏ các câu lệnh điều kiện trong lớp sử dụng.
- Mẫu này có thể áp dụng cho nhiều trường hợp khác nhau, bất cứ khi nào cần thay đổi quy tắc xử lý trong thời gian chạy.
- Khách hàng chịu trách nhiệm lựa chọn chiến lược phù hợp và truyền vào đối tượng
PaymentContext.