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

Java 裝飾器模式入門與咖啡加料實戰

     編輯:Java 相關知識

裝飾器模式屬於結構型模式,動態地給物件添加新職責,比繼承更靈活。本文通過「咖啡 + 牛奶/巧克力/糖」的經典案例,展示裝飾器結構、代碼實現、多層裝飾組合與遞歸調用鏈。

模式結構


┌──────────────┐
│  Component   │◀────── 介面:定義核心行為 method()
└──────┬───────┘
       │
       ├──────────────────┐
       ▼                  ▼
┌─────────────┐    ┌─────────────┐
│ ConcreteComp│    │  Decorator  │ (持有 Component 引用)
│   Coffee    │    └──────┬──────┘
└─────────────┘           │
                          │
              ┌───────────┴───────────┐
              ▼                       ▼
      ┌───────────────┐        ┌───────────────┐
      │ ConcreteDecoA │        │ ConcreteDecoB │
      │  Milk+Sugar   │        │  Chocolate    │
      └───────────────┘        └───────────────┘

核心代碼實現


// 1. 組件介面
interface Component {
    void method();
}

// 2. 具體組件:基礎咖啡
class Coffee implements Component {
    @Override public void method() {
        System.out.println("倒入咖啡");
    }
}

// 3. 抽象裝飾器:持有被裝飾對象,轉發核心方法
class Decorator implements Component {
    protected Component component;
    public Decorator(Component component) { this.component = component; }
    @Override public void method() { component.method(); }
}

// 4. 具體裝飾器 A:牛奶 + 糖
class ConcreteDecorateA extends Decorator {
    public ConcreteDecorateA(Component c) { super(c); }
    private void addMilk() { System.out.println("倒入牛奶"); }
    private void addSugar() { System.out.println("加入糖"); }
    @Override public void method() {
        super.method();   // 先執行被裝飾對象邏輯
        addMilk();        // 再添加自己的行為
        addSugar();
    }
}

// 5. 具體裝飾器 B:巧克力
class ConcreteDecorateB extends Decorator {
    public ConcreteDecorateB(Component c) { super(c); }
    private void addChocolate() { System.out.println("加入巧克力"); }
    @Override public void method() {
        super.method();
        addChocolate();
    }
}

客戶端組合使用


public class TestDecoratePattern {
    public static void main(String[] args) {
        // 基礎咖啡
        Component coffee = new Coffee();
        coffee.method();
        // 輸出:倒入咖啡

        System.out.println("--- 單層裝飾:牛奶+糖 ---");
        Component withMilkSugar = new ConcreteDecorateA(coffee);
        withMilkSugar.method();
        // 輸出:倒入咖啡 → 倒入牛奶 → 加入糖

        System.out.println("--- 雙層裝飾:(咖啡+牛奶+糖)+巧克力 ---");
        Component withChoco = new ConcreteDecorateB(withMilkSugar);
        withChoco.method();
        // 輸出:倒入咖啡 → 倒入牛奶 → 加入糖 → 加入巧克力

        System.out.println("--- 鏈式構建:巧克力(牛奶+糖(咖啡)) ---");
        Component chain1 = new ConcreteDecorateB(new ConcreteDecorateA(new Coffee()));
        chain1.method();

        System.out.println("--- 逆序:牛奶+糖(巧克力(咖啡)) ---");
        Component chain2 = new ConcreteDecorateA(new ConcreteDecorateB(new Coffee()));
        chain2.method();
        // 輸出順序不同:倒入咖啡 → 加入巧克力 → 倒入牛奶 → 加入糖
    }
}

執行結果對比

構建方式輸出順序說明
new ConcreteDecorateA(coffee)咖啡 → 牛奶 → 糖單層裝飾
new ConcreteDecorateB(withMilkSugar)咖啡 → 牛奶 → 糖 → 巧克力外層裝飾在內層之後執行
new ConcreteDecorateB(new ConcreteDecorateA(new Coffee()))咖啡 → 牛奶 → 糖 → 巧克力鏈式構建,內層優先
new ConcreteDecorateA(new ConcreteDecorateB(new Coffee()))咖啡 → 巧克力 → 牛奶 → 糖裝飾順序改變行為順序

核心原理:遞歸轉發鏈


// 簡化的調用鏈
chain2.method()  // ConcreteDecorateA.method()
    → super.method()  // Decorator.method() → ConcreteDecorateB.method()
        → super.method()  // Decorator.method() → Coffee.method()
            → "倒入咖啡"
        → "加入巧克力"
    → "倒入牛奶"
    → "加入糖"

每個裝飾器調用 `super.method()` 觸發內層邏輯,形成**洋蔥模型**調用鏈:請求從外層進入,逐層向內傳遞到核心組件,響應再逐層向外返回,各層可在前置/後置位置插入邏輯。

Java JDK 內建裝飾器實例


// 經典嵌套用法
new BufferedReader(
    new InputStreamReader(
        new GZIPInputStream(
            new FileInputStream("data.gz"))));

裝飾器 vs 繼承 vs 組合

基礎類裝飾器增強功能
InputStreamBufferedInputStream緩衝讀取
InputStreamGZIPInputStream解壓縮
InputStreamDataInputStream基本類型讀取
OutputStreamBufferedOutputStream緩衝寫入
Reader/WriterBufferedReader/Writer緩衝字符讀寫
CollectionCollections.synchronizedList()線程安全包裝
CollectionCollections.unmodifiableList()不可變視圖
維度繼承裝飾器組合(策略模式)
靈活性靜態、編譯期固定動態、運行期組合動態、運行期替換
擴展性子類爆炸單一職責、任意組合策略類獨立擴展
透明性子類即父類裝飾器與被裝飾者同介面持有策略介面
適用場景is-a 關係穩定橫切關注點、動態增強算法族、行為可插拔

最佳實踐提醒

  1. 保持介面精簡:Component 介面只定義核心行為,避免膨脹。
  2. 裝飾器不應依賴具體組件:只依賴 Component 介面,保證可嵌套任意層級。
  3. 避免過度設計:若擴展點固定、層級少,繼承或組合可能更簡單。
  4. 命名規範:`XxxDecorator` 或 `XxxWrapper`,語義清晰。
  5. Spring AOP 本質即動態代理裝飾器:理解裝飾器有助於掌握 AOP 原理。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved