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

裝飾模式深度解析:從 UML 到實戰的動態擴展藝術

     編輯:Java 程式設計入門

當你需要在不修改原有類、不使用繼承的前提下,為物件「動態地、透明地」增加職責時,裝飾模式是教科書級的解決方案。它以組合取代繼承,實現「開放擴展、關閉修改」的開閉原則精髓。

核心角色與 UML 結構

Decorator Pattern UML

角色類別/介面職責
Component介面或抽象類定義被裝飾物件的核心契約 (如 doSomething())
ConcreteComponent實作類最基礎、最核心的實作 (如 ConcreteComponent)
Decorator抽象類持有 Component 參考,委派核心行為,定義擴展點
ConcreteDecorator具體裝飾類在委派前/後添加額外邏輯 (如 ConcreteDecoratorA)

通用骨架代碼 (Java)

// 1. 抽象構件
public abstract class Component {
    public abstract void doSomething();
}

// 2. 具體構件
public class ConcreteComponent extends Component {
    @Override public void doSomething() {
        System.out.println("核心業務邏輯");
    }
}

// 3. 抽象裝飾者 (關鍵:持有 Component 參考)
public abstract class Decorator extends Component {
    protected Component component;
    public Decorator(Component component) { this.component = component; }
    @Override public void doSomething() { component.doSomething(); } // 預設委派
}

// 4. 具體裝飾者 A:前置增強
public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component c) { super(c); }
    @Override public void doSomething() {
        before();           // 新增:前置邏輯
        super.doSomething(); // 委派核心
    }
    private void before() { System.out.println("DecoratorA: 前置處理"); }
}

// 5. 具體裝飾者 B:後置增強
public class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component c) { super(c); }
    @Override public void doSomething() {
        super.doSomething(); // 委派核心
        after();            // 新增:後置邏輯
    }
    private void after() { System.out.println("DecoratorB: 後置處理"); }
}

// 6. 客戶端:像剝洋蔥一樣層層包裹
public class Client {
    public static void main(String[] args) {
        Component core = new ConcreteComponent();
        core = new ConcreteDecoratorA(core); // 第一層
        core = new ConcreteDecoratorB(core); // 第二層
        core.doSomething(); // 執行完整鏈路
    }
}
// 輸出:
// DecoratorA: 前置處理
// 核心業務邏輯
// DecoratorB: 後置處理

實戰案例:電商訂單「雙十一」促銷疊加

場景:基礎訂單需疊加「滿減」、「優惠券」、「會員折扣」、「首單禮」等促銷規則,規則頻繁變動、組合多變。

Order Decorator UML

// Component: 訂單核心介面
public interface Order {
    BigDecimal calculate(); // 計算最終金額
    String getDetail();     // 明細描述
}

// ConcreteComponent: 基礎訂單
public class BaseOrder implements Order {
    private BigDecimal amount;
    public BaseOrder(BigDecimal amount) { this.amount = amount; }
    public BigDecimal calculate() { return amount; }
    public String getDetail() { return "基礎金額: " + amount; }
}

// Decorator: 抽象促銷裝飾者
public abstract class PromotionDecorator implements Order {
    protected Order order;
    public PromotionDecorator(Order order) { this.order = order; }
    public BigDecimal calculate() { return order.calculate(); }
    public String getDetail() { return order.getDetail(); }
}

// ConcreteDecorators: 具體促銷規則
public class FullReductionDecorator extends PromotionDecorator {
    private BigDecimal threshold, reduction;
    public FullReductionDecorator(Order o, BigDecimal t, BigDecimal r) { super(o); threshold=t; reduction=r; }
    @Override public BigDecimal calculate() {
        BigDecimal amt = super.calculate();
        return amt.compareTo(threshold) >= 0 ? amt.subtract(reduction) : amt;
    }
    @Override public String getDetail() { return super.getDetail() + " | 滿減: " + reduction; }
}

public class CouponDecorator extends PromotionDecorator {
    private BigDecimal couponValue;
    public CouponDecorator(Order o, BigDecimal v) { super(o); couponValue=v; }
    @Override public BigDecimal calculate() { return super.calculate().subtract(couponValue); }
    @Override public String getDetail() { return super.getDetail() + " | 優惠券: " + couponValue; }
}

public class MemberDiscountDecorator extends PromotionDecorator {
    private BigDecimal rate; // 0.9 = 9 折
    public MemberDiscountDecorator(Order o, BigDecimal r) { super(o); rate=r; }
    @Override public BigDecimal calculate() { return super.calculate().multiply(rate).setScale(2, RoundingMode.HALF_UP); }
    @Override public String getDetail() { return super.getDetail() + " | 會員折扣: " + rate; }
}

// Client: 動態組合促銷策略
public class OrderService {
    public Order buildPromotedOrder(Order base, User user, List coupons) {
        Order decorated = base;
        // 1. 滿減
        decorated = new FullReductionDecorator(decorated, new BigDecimal("200"), new BigDecimal("30"));
        // 2. 優惠券
        if (!coupons.isEmpty()) decorated = new CouponDecorator(decorated, coupons.get(0).getValue());
        // 3. 會員折扣
        if (user.isVip()) decorated = new MemberDiscountDecorator(decorated, new BigDecimal("0.9"));
        return decorated;
    }
}

優缺點權衡與適用場景

優點缺點 / 注意點
裝飾類與被裝飾類解耦,單一職責過多裝飾層導致除錯困難、堆疊順序敏感
替代繼承爆炸,支援動態組合身份判斷失效:decorated instanceof ConcreteComponent 為 false
符合開閉原則,擴展不修改核心若頻繁新增裝飾類,考慮責任鏈或策略模式替代
可疊加多層,還原 is-a 關係序列化/反序列化需特殊處理包裹鏈

JDK 內建最佳實踐:IO 流與 Collections

  • BufferedReader 裝飾 FileReader:增加緩衝讀取能力
  • GZIPInputStream 裝飾 FileInputStream:增加解壓縮能力
  • Collections.synchronizedList() 裝飾 ArrayList:增加線程安全能力
  • Collections.unmodifiableList():增加唯讀保護能力
這些經典案例證明:裝飾模式不是理論玩具,而是 Java 標準庫處理「橫切能力增強」的基石模式。

總結

裝飾模式以「包裹 + 委派 + 增強」三步曲,優雅解決動態職責疊加難題。下次當你面臨「如果加上 A 功能、再加上 B 功能、順序還可能互換」的需求時,請優先考慮裝飾模式——它能讓核心業務邏輯保持純粹,而將變化點封裝在獨立、可組合的裝飾類中。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved