裝飾器模式:動態地給物件新增職責,如同牆面刷漆層層疊加。相較於繼承產生大量子類別,裝飾器提供更靈活的擴展方式。
BufferedReader(new FileReader(file)) 即裝飾器鏈// 共同超類型
public interface Human {
void wearClothes();
void walkToWhere();
}
// 抽象裝飾者:持有被裝飾者,預設委派
public abstract class Decorator implements Human {
protected Human human;
public Decorator(Human human) { this.human = human; }
@Override public void wearClothes() { human.wearClothes(); }
@Override public void walkToWhere() { human.walkToWhere(); }
}
// 第零層:進房子、找地圖
public class DecoratorZero extends Decorator {
public DecoratorZero(Human human) { super(human); }
private void goHome() { System.out.println("進房子。。"); }
private void findMap() { System.out.println("書房找找Map。。"); }
@Override public void wearClothes() { super.wearClothes(); goHome(); }
@Override public void walkToWhere() { super.walkToWhere(); findMap(); }
}
// 第一層:去衣櫃、在地圖找地點
public class DecoratorFirst extends Decorator {
public DecoratorFirst(Human human) { super(human); }
private void goClothespress() { System.out.println("去衣櫃找找看。。"); }
private void findPlaceOnMap() { System.out.println("在Map上找找。。"); }
@Override public void wearClothes() { super.wearClothes(); goClothespress(); }
@Override public void walkToWhere() { super.walkToWhere(); findPlaceOnMap(); }
}
// 第二層:找到衣服、找到目標地點
public class DecoratorTwo extends Decorator {
public DecoratorTwo(Human human) { super(human); }
private void findClothes() { System.out.println("找到一件D&G。。"); }
private void findTheTarget() { System.out.println("在Map上找到神秘花園和城堡。。"); }
@Override public void wearClothes() { super.wearClothes(); findClothes(); }
@Override public void walkToWhere() { super.walkToWhere(); findTheTarget(); }
}
public class Person implements Human {
@Override public void wearClothes() { System.out.println("穿什麼呢。。"); }
@Override public void walkToWhere() { System.out.println("去哪裡呢。。"); }
}
public class Test {
public static void main(String[] args) {
Human person = new Person();
// 由內而外包裝:Person → Zero → First → Two
Decorator decorator = new DecoratorTwo(
new DecoratorFirst(new DecoratorZero(person))
);
decorator.wearClothes();
decorator.walkToWhere();
}
}
穿什麼呢。。 // Person 基礎行為 進房子。。 // Zero 新增 去衣櫃找找看。。 // First 新增 找到一件D&G。。 // Two 新增 去哪裡呢。。 // Person 基礎行為 書房找找Map。。 // Zero 新增 在Map上找找。。 // First 新增 在Map上找到神秘花園和城堡。。 // Two 新增
執行順序鐵律:每層 super.method() 先執行內層邏輯,再執行自身新增邏輯,形成「由內向外」的洋蔥模型。
| 角色 | 漢堡案例 | 人員案例 |
|---|---|---|
| Component | Humburger (抽象) | Human (介面) |
| ConcreteComponent | ChickenBurger | Person |
| Decorator | Condiment (抽象) | Decorator (抽象類) |
| ConcreteDecorator | Lettuce, Chilli | DecoratorZero, First, Two |
// 漢堡基類
public abstract class Humburger {
protected String name;
public String getName() { return name; }
public abstract double getPrice();
}
// 基礎漢堡
public class ChickenBurger extends Humburger {
public ChickenBurger() { name = "雞腿堡"; }
@Override public double getPrice() { return 10; }
}
// 配料抽象裝飾者
public abstract class Condiment extends Humburger {
public abstract String getName();
}
// 生菜裝飾
public class Lettuce extends Condiment {
private Humburger hamburger;
public Lettuce(Humburger hamburger) { this.hamburger = hamburger; }
@Override public String getName() { return hamburger.getName() + " 加生菜"; }
@Override public double getPrice() { return hamburger.getPrice() + 1.5; }
}
// 辣椒裝飾(免費)
public class Chilli extends Condiment {
private Humburger hamburger;
public Chilli(Humburger hamburger) { this.hamburger = hamburger; }
@Override public String getName() { return hamburger.getName() + " 加辣椒"; }
@Override public double getPrice() { return hamburger.getPrice(); }
}
public class Test {
public static void main(String[] args) {
Humburger burger = new ChickenBurger();
System.out.println(burger.getName() + " 價錢:" + burger.getPrice());
// 雞腿堡 價錢:10.0
Humburger withLettuce = new Lettuce(burger);
System.out.println(withLettuce.getName() + " 價錢:" + withLettuce.getPrice());
// 雞腿堡 加生菜 價錢:11.5
Humburger withChilli = new Chilli(burger);
System.out.println(withChilli.getName() + " 價錢:" + withChilli.getPrice());
// 雞腿堡 加辣椒 價錢:10.0
Humburger combo = new Chilli(new Lettuce(burger));
System.out.println(combo.getName() + " 價錢:" + combo.getPrice());
// 雞腿堡 加生菜 加辣椒 價錢:11.5
}
}
抽象裝飾者持有 Component 引用,所有操作預設委派給被裝飾者,具體裝飾者選擇性擴展特定方法。
Decorator dt = new DecoratorTwo(new DecoratorFirst(new DecoratorZero(human))) 中,抽象類 Decorator 依賴具體實現(由建構子注入),而非反過來。
新增裝飾行為只需新增 Decorator 子類,無須修改既有類別。擴展發生在子類,修改關閉在抽象層。
每個裝飾者只負責一項具體功能擴展(如價格計算、名稱拼接、行為新增)。
new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))| 誤區 | 正確做法 |
|---|---|
| 裝飾者修改被裝飾者狀態 | 僅新增行為,不破壞原有語義 |
| 過度使用導致層級過深 | 層級超過 3-4 層考慮重構或策略模式 |
| 混淆裝飾器與代理模式 | 代理控制存取,裝飾器新增職責 |
裝飾器模式以「組合替代繼承」,實現運行時動態擴展物件功能。掌握其核心——共同超類型、持有被裝飾者引用、委派+選擇性擴展,即可靈活應對各類功能疊加場景。Java I/O 體系是最佳學習範本,建議親手追蹤源碼體會洋蔥模型的優雅。