Decorator(裝飾者)模式動態為物件新增額外職責,猶如牆面刷油漆。相較於繼承產生大量子類別、編譯期靜態決定功能擴充,Decorator 提供「即插即用」的執行期動態組合彈性。
模式核心要素:
基礎 Counter 類別提供 increment()、decrement()、read_value() 方法。需動態新增:
UpperLimit)LowerLimit)初版實作中,Decorator 繼承 Counter 並聚合 Counter 參考:
class Decorator extends Counter {
Counter counter;
public Decorator(Counter c) {
super(c); // 父類別複製 counter.value
counter = c; // 自身聚合 counter 參考
}
}
new LowerLimit(new Counter(6)))UpperLimit 同樣出現此問題。
觀察 LowerLimit.decrement() 開頭兩行追蹤輸出:
Class value : 7 // 呼叫父類別繼承而來的 read_value()
Dec value : 6 // 呼叫聚合物件 counter.read_value()
存在兩份 value:
Counter 複製而來的 value(位於 Decorator 繼承體系中)counter 參考的原始物件 value產生原因:工廠傳入匿名 Counter 物件 → Decorator 建構子先呼叫 super(c) 讓父類別複製 value → 再將參考存入自身 counter 成員。導致同一邏輯實體擁有兩份獨立狀態。
LowerLimit 僅覆寫 decrement(),呼叫 read_value() 與 increment() 時走父類別邏輯(操作第一份 value);呼叫 decrement() 時走自身邏輯(操作第二份 value)。雙軌並行造成狀態不同步。
Decorator 模式本意為「避免繼承、採用委派」。解決核心在於:
countersuper(c) 複製數值)read_value()、increment() 等委派實作)啟用修正後的 UpperLimit 範例:
class UpperLimit extends Decorator {
public UpperLimit(Counter c) { super(c); }
public void increment() {
if (counter.read_value() > 20) {
System.out.println("Too High");
} else {
counter.increment();
}
}
public void decrement() { counter.decrement(); }
public int read_value() { return counter.read_value(); }
}
Decorator 建構子參數代表「既有類別基礎」,自身聚合物件必須持有該參數參考,所有方法必須重寫委派,否則將陷入「繼承陷阱」:父類別操作複製的狀態、子類別操作聚合物件的狀態,雙軌並行導致狀態分歧。
此案例深刻說明:設計模式不僅是結構圖,更蘊含執行期行為契約。Decorator 模式要求「介面繼承 + 物件組合 + 完全委派」,任何保留繼承實作細節的做法皆違背模式初衷,必生 Bug。