書店推出多重折扣規則:
系統需彈性支援規則擴充、組合與上限控制。
+---------------------+ +---------------------+ +---------------------+
| Strategy 模式 | | Factory Method | | Decorator 模式 |
| (單一規則演算法) | | (書型別↔策略配對) | | (疊加規則+上限) |
+---------------------+ +---------------------+ +---------------------+
↑ ↑ ↑
DiscountStrategy Publisher 介面 Order 介面
├─ NoDiscountStrategy ├─ ComputerBookPublish ├─ PayOrder (基礎)
├─ FlatRateStrategy ├─ ManagementBookPublish ├─ CopyDecorator (+5本)
└─ PercentageStrategy └─ NewReleaseBookPublisher └─ PayDecorator (上限50)
public abstract class DiscountStrategy {
protected final double price;
public DiscountStrategy(double price) { this.price = price; }
public abstract double calculateDiscount();
}
public class NoDiscountStrategy extends DiscountStrategy {
public NoDiscountStrategy(double price) { super(price); }
public double calculateDiscount() { return 0; }
}
public class FlatRateStrategy extends DiscountStrategy {
private final double discount;
public FlatRateStrategy(double price, double discount) { super(price); this.discount = discount; }
public double calculateDiscount() { return discount; }
}
public class PercentageStrategy extends DiscountStrategy {
private final double percent;
public PercentageStrategy(double price, double percent) { super(price); this.percent = Math.min(percent, 1.0); }
public double calculateDiscount() { return price * percent; }
}
public interface Publisher {
Book bookFactory(String name, double price);
}
public class ComputerBookPublish implements Publisher {
private final double discount;
public ComputerBookPublish(double discount) { this.discount = discount; }
public Book bookFactory(String name, double price) {
Book b = new ComputerBook(name, price);
b.setStrategy(new FlatRateStrategy(price, discount));
return b;
}
}
// ManagementBookPublish、NewReleaseBookPublisher 同理
public abstract class Book {
protected final String name;
protected final double price;
protected DiscountStrategy strategy;
public Book(String name, double price) { this.name = name; this.price = price; }
public void setStrategy(DiscountStrategy s) { this.strategy = s; }
public double getDiscount() { return strategy.calculateDiscount(); }
// getters...
}
public interface Order {
void buy(int copies, String name, int price, int type);
double originalPay();
double actualPay();
double discount();
int getCopies();
void addPolicy(); // 裝飾鏈擴充點
}
public class PayOrder implements Order {
private final Map items = new HashMap<>();
private double totalPrice = 0;
private double totalDiscount = 0;
private int totalCopies = 0;
// 建構子注入策略參數...
public void buy(int copies, String name, int price, int type) {
Book book = createBookByType(name, price, type); // 使用 Publisher
totalCopies += copies;
items.merge(name, copies, Integer::sum);
totalPrice += copies * price;
totalDiscount += copies * book.getDiscount();
}
// getters / addPolicy() 空實作...
}
public abstract class OrderDecorator implements Order {
protected final Order delegate;
public OrderDecorator(Order delegate) { this.delegate = delegate; }
// 所有方法轉發 delegate,addPolicy() 預設轉發
public void addPolicy() { delegate.addPolicy(); }
}
public class CopyDecorator extends OrderDecorator {
public CopyDecorator(Order o) { super(o); }
public void addPolicy() {
if (getCopies() > 5) setDiscount(discount() + 20);
super.addPolicy();
}
}
public class PayDecorator extends OrderDecorator {
public PayDecorator(Order o) { super(o); }
public void addPolicy() {
if (discount() > 50) setDiscount(50);
super.addPolicy();
}
}
public class Client {
public static void main(String[] args) {
Order order = new PayOrder(10, 0.1); // 計算機折扣10、經管10%
order.buy(1, "Java", 40, BookType.COMPUTER);
order.buy(1, "C++", 60, BookType.COMPUTER);
order.buy(1, "Design Pattern", 100, BookType.COMPUTER);
order.buy(1, "Manager", 60, BookType.MANAGEMENT);
order.buy(1, "Apo", 20, BookType.NEW_RELEASE);
order.buy(1, "droAq", 20, BookType.NEW_RELEASE);
System.out.println("--- 僅基礎規則 ---");
print(order);
// 疊加裝飾:順序很重要!先 CopyDecorator 再 PayDecorator
order = new CopyDecorator(new PayDecorator(order));
order.addPolicy();
System.out.println("--- 套用 5本+20元 + 上限50元 ---");
print(order);
}
static void print(Order o) {
System.out.printf("原價: %.1f, 折扣: %.1f, 實付: %.1f%n",
o.originalPay(), o.discount(), o.actualPay());
}
}
--- 僅基礎規則 ---
原價: 300.0, 抂扣: 36.0, 實付: 264.0
--- 套用 5本+20元 + 上限50元 ---
原價: 300.0, 折扣: 50.0, 實付: 250.0
解析:基礎折扣 36 (3×10 + 60×0.1) → +20 (6本>5) = 56 → 上限截斷 50。
| 模式 | 解決問題 | 擴充性 |
|---|---|---|
| Strategy | 折扣演算法變化隔離 | 新增折扣型別只加類別,不動既有代碼 |
| Factory Method | 書類別與策略強綁定封裝 | 新增書類別只加 Publisher 實作 |
| Decorator | 訂單級規則疊加、順序控制、上限攔截 | 新規則只加 Decorator 子類,組合靈活 |