首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 設計模式實戰:策略+工廠方法+裝飾器打造圖書折扣系統

     編輯:Java 相關知識

需求描述

書店推出多重折扣規則:

  1. 新書:無折扣
  2. 計算機類:固定折扣 10 元
  3. 經管類:書價 10% 折扣
  4. 購買 5 本以上:額外固定折扣 20 元
  5. 總折扣上限 50 元

系統需彈性支援規則擴充、組合與上限控制。

架構設計:三大模式協作


+---------------------+      +---------------------+      +---------------------+
|   Strategy 模式     |      |  Factory Method     |      |   Decorator 模式    |
|  (單一規則演算法)   |      |  (書型別↔策略配對)  |      |  (疊加規則+上限)    |
+---------------------+      +---------------------+      +---------------------+
        ↑                            ↑                            ↑
  DiscountStrategy           Publisher 介面               Order 介面
  ├─ NoDiscountStrategy      ├─ ComputerBookPublish      ├─ PayOrder (基礎)
  ├─ FlatRateStrategy        ├─ ManagementBookPublish    ├─ CopyDecorator (+5本)
  └─ PercentageStrategy      └─ NewReleaseBookPublisher  └─ PayDecorator (上限50)

核心代碼實作

1. Strategy:折扣演算法族

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

2. Factory Method:書類別與策略綁定

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 同理

3. Book 抽象基類持有策略引用

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...
}

4. Decorator:訂單層級疊加規則

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。

設計亮點總結

裝飾器順序關鍵

new CopyDecorator(new PayDecorator(order)) 表示:

  1. 先執行 CopyDecorator.addPolicy() (滿 5 本 +20)
  2. 再執行 PayDecorator.addPolicy() (上限 50)

若順序顛倒,上限會先截斷基礎折扣,導致滿 5 本優惠失效。

結語

此案例展示三大經典模式在真實業務中的組合威力:Strategy 封裝演算法變化、Factory Method 封裝物件創建邏輯、Decorator 實現橫切關注點的動態組合。掌握模式組合,比單獨記憶單一模式結構更具實戰價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
模式解決問題擴充性
Strategy折扣演算法變化隔離新增折扣型別只加類別,不動既有代碼
Factory Method書類別與策略強綁定封裝新增書類別只加 Publisher 實作
Decorator訂單級規則疊加、順序控制、上限攔截新規則只加 Decorator 子類,組合靈活