裝飾模式(Decorator Pattern),又稱包裝模式,是結構型設計模式中的經典之作。它在不改變原類別、不使用繼承的前提下,動態地為物件擴展職責,完美詮釋了「開放封閉原則」與「合成復用原則」。本文將從定義、核心角色、與繼承的差異、程式碼實戰、到 Java IO 體系中的實際應用,全方位剖析此模式。
| 角色 | 說明 | Java IO 對應範例 |
|---|---|---|
| Component(抽象構件) | 定義物件介面,規範核心行為 | InputStream、Reader |
| ConcreteComponent(具體構件) | 被裝飾的核心物件 | FileInputStream、FileReader |
| Decorator(抽象裝飾者) | 持有 Component 參考,實作相同介面,委派給被裝飾者 | FilterInputStream、BufferedReader |
| ConcreteDecorator(具體裝飾者) | 在委派前後增加具體行為 | BufferedInputStream、DataInputStream、GZIPInputStream |
| 維度 | 繼承 | 裝飾模式 |
|---|---|---|
| 綁定時機 | 編譯期(靜態) | 執行期(動態) |
| 功能組合 | 單一繼承鏈,排列組合需建大量子類 | 任意組合裝飾類,零類別爆炸 |
| 擴展對象 | 類別功能 | 物件實例功能 |
| 透明性 | 子類型即父類型 | 裝飾者與被裝飾者實作相同介面,客戶端無感 |
// 1. 抽象構件
public interface Component {
void doSomething();
}
// 2. 具體構件
public class ConcreteComponent implements Component {
public void doSomething() { System.out.println("功能A"); }
}
// 3. 抽象裝飾者(持有 Component 參考)
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component c) { this.component = c; }
public void doSomething() { component.doSomething(); } // 預設委派
}
// 4. 具體裝飾者 1:增加功能 B
public class ConcreteDecorator1 extends Decorator {
public ConcreteDecorator1(Component c) { super(c); }
public void doSomething() {
super.doSomething(); // 執行核心/前一層功能
doAnotherThing(); // 新增功能
}
private void doAnotherThing() { System.out.println("功能B"); }
}
// 5. 具體裝飾者 2:增加功能 C
public class ConcreteDecorator2 extends Decorator {
public ConcreteDecorator2(Component c) { super(c); }
public void doSomething() {
super.doSomething();
doAnotherThing();
}
private void doAnotherThing() { System.out.println("功能C"); }
}
// 6. 客戶端:像搭積木一樣組合
public class Client {
public static void main(String[] args) {
Component c = new ConcreteDecorator1(
new ConcreteDecorator2(
new ConcreteComponent()));
c.doSomething();
// 輸出:功能A → 功能C → 功能B(由內而外疊加)
}
}
// 核心節點(ConcreteComponent)
FileInputStream fis = new FileInputStream("data.txt");
// 層層裝飾:緩衝 → 資料型別轉換 → 物件序列化
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
ObjectInputStream ois = new ObjectInputStream(dis);
// 客戶端只看到 InputStream 介面,完全不知內部已疊加三層功能
int i = dis.readInt();
Object obj = ois.readObject();
每一層 XXXInputStream 都是具體裝飾者,新增緩衝、基本型別讀取、物件反序列化等能力,卻統一實作 InputStream 介面,完美示範裝飾模式精髓。
instanceof 判斷需謹慎。裝飾模式以「組合取代繼承」,在執行期為物件動態貼上功能標籤,是 Java IO、Servlet Filter、Spring AOP 代理鏈等眾多框架的核心架構基石。掌握其「同介面、持引用、轉發、增強」四步曲,即可輕鬆駕馭靈活的功能擴展藝術。