裝飾器模式以組合替代繼承,動態為對象添加職責,是開閉原則的經典實踐。本文對比繼承與裝飾兩種擴展方式,透過房屋裝修、IO 流、自定義裝飾器三個層級案例,展示模式核心價值與實戰技巧。
// 繼承方案:類爆炸
abstract class House { abstract void show(); }
class PingFang extends House { void show() { print("平房"); } }
class LouFang extends House { void show() { print("樓房"); } }
// 想加田園風格?
class TianYuanPingFang extends PingFang { void show() { super.show(); print("田園"); } }
class TianYuanLouFang extends LouFang { void show() { super.show(); print("田園"); } }
// 想再加歐式風格?再加 2 個類...
// 組合數 = 房屋類型 × 風格類型,指數級增長
House)PingFang, LouFang)TianYuan, OuShi)// 抽象構件
abstract class House {
public abstract void show();
}
// 具體構件
class PingFang extends House {
public void show() { System.out.print("平房"); }
}
class LouFang extends House {
public void show() { System.out.print("樓房"); }
}
// 抽象裝飾器
abstract class HouseDecorator extends House {
protected House house;
public HouseDecorator(House house) { this.house = house; }
public void show() { house.show(); } // 默認委派
}
// 具體裝飾器:田園風格
class TianYuan extends HouseDecorator {
public TianYuan(House house) { super(house); }
@Override public void show() {
super.show(); // 執行被裝飾對象邏輯
System.out.print(" + 田園風格");
}
}
// 具體裝飾器:歐式風格
class OuShi extends HouseDecorator {
public OuShi(House house) { super(house); }
@Override public void show() {
super.show();
System.out.print(" + 歐式風格");
}
}
// 客戶端:靈活組合
public class DecoratorDemo {
public static void main(String[] args) {
House house = new PingFang();
house = new TianYuan(house); // 平房 + 田園
house = new OuShi(house); // 平房 + 田園 + 歐式
house.show(); // 輸出:平房 + 田園風格 + 歐式風格
}
}
// 裝飾器鏈:節點流 + 多層處理流
InputStream in = new FileInputStream("data.txt"); // 節點流
in = new BufferedInputStream(in); // 緩衝裝飾
in = new DataInputStream(in); // 數據類型讀取裝飾
in = new GZIPInputStream(in); // 解壓裝飾
// 每層裝飾器增強單一職責,靈活組合
// new BufferedReader(new InputStreamReader(new FileInputStream(...)))
設計精髓:FilterInputStream 為抽象裝飾器,持有 InputStream in,各具體裝飾器 (BufferedInputStream, DataInputStream) 僅關注單一增強邏輯。
interface Logger { void log(String msg); }
class ConsoleLogger implements Logger {
public void log(String msg) { System.out.println(msg); }
}
abstract class LoggerDecorator implements Logger {
protected Logger logger;
public LoggerDecorator(Logger logger) { this.logger = logger; }
public void log(String msg) { logger.log(msg); }
}
class TimestampDecorator extends LoggerDecorator {
public TimestampDecorator(Logger logger) { super(logger); }
@Override public void log(String msg) {
logger.log("[" + LocalDateTime.now() + "] " + msg);
}
}
class LevelDecorator extends LoggerDecorator {
private String level;
public LevelDecorator(Logger logger, String level) { super(logger); this.level = level; }
@Override public void log(String msg) {
logger.log("[" + level + "] " + msg);
}
}
// 使用:控制台 + 時間戳 + INFO 級別
Logger logger = new LevelDecorator(new TimestampDecorator(new ConsoleLogger()), "INFO");
logger.log("服務啟動"); // [2024-01-15T10:30:00] [INFO] 服務啟動
| 模式 | 核心意圖 | 關系 | 關鍵差異 |
|---|---|---|---|
| 裝飾器 | 動態添加職責 | 組合 (has-a) | 透明擴展,支援疊加,遵循開閉原則 |
| 繼承 | 靜態擴展 | 繼承 (is-a) | 編譯期固定,類爆炸,破壞封裝 |
| 代理 | 控制訪問 | 組合 | 代理生命週期通常與被代理綁定,不疊加 |
| 適配器 | 介面轉換 | 組合/繼承 | 事後補救,使不兼容介面協同工作 |