裝飾模式的定義:
裝飾模式(Decorator Pattern)是一種結構型設計模式,它允許你動態地給一個對象添加一些額外的職責。就增加功能來說,裝飾模式相比生成子類更為靈活。
何時應用裝飾模式?
1.當需要動態地給一個對象增加功能時:如果你需要在運行時給一個對象增加新的職責,而不是在編譯時,那么裝飾模式是一個好的選擇。
2.當使用繼承會導致大量子類時:如果你使用繼承來擴展對象的功能,那么可能會產生大量的子類,導致系統難以管理和維護。使用裝飾模式可以避免這個問題。
3.當需要透明地增強對象的功能時:裝飾模式允許你透明地增強對象的功能,這意味著客戶端代碼可以像使用原始對象一樣使用裝飾后的對象,而不需要知道對象已經被裝飾了。
需要注意什么?
-
避免過度使用:雖然裝飾模式很靈活,但過度使用它可能會導致代碼變得復雜和難以理解。因此,在決定是否使用裝飾模式時,需要權衡其優點和缺點。
-
性能考慮:由于裝飾模式會在運行時動態地添加功能,因此可能會帶來一些性能開銷。如果性能是一個關鍵問題,那么需要仔細考慮是否使用裝飾模式。
-
設計好接口:裝飾模式依賴于良好的接口設計。如果接口設計得不好,那么裝飾模式可能會變得難以使用和維護。
重要的構造部分:
-
組件(Component):這是一個接口或抽象類,它定義了對象的核心職責。
-
具體組件(ConcreteComponent):這是實現了組件接口的具體類。
-
裝飾器(Decorator):這也是一個接口或抽象類,它實現了組件接口,并持有一個對組件對象的引用。裝飾器接口通常會增加一些新的方法或覆蓋組件接口中的方法,以提供額外的功能。
-
具體裝飾器(ConcreteDecorator):這是實現了裝飾器接口的具體類。具體裝飾器會持有對組件對象的引用,并在需要時調用組件對象的方法。同時,具體裝飾器還可以添加自己的功能。
-
客戶端(Client):客戶端代碼通過組件接口與對象交互,而不需要知道對象是否被裝飾了。
示例實現:
以下是一個簡單的裝飾模式示例,它模擬了一個咖啡訂單系統。在這個系統中,可以為咖啡添加不同的調料,如牛奶和糖,這些調料就是裝飾器。
首先,定義一個Beverage接口,它代表了一種飲料:
public interface Beverage { String getDescription(); double cost();
}
接著,創建一個實現了Beverage接口的DarkRoast類,它代表了一種深焙咖啡:
public class DarkRoast implements Beverage { @Override public String getDescription() { return "Dark Roast Coffee"; } @Override public double cost() { return 1.99; }
}
現在創建一個CondimentDecorator抽象類,它實現了Beverage接口并持有一個Beverage對象的引用。這個類將作為所有裝飾器的基類:
public abstract class CondimentDecorator implements Beverage { protected Beverage beverage; public CondimentDecorator(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription(); } @Override public double cost() { return beverage.cost(); }
}
接下來創建兩個具體的裝飾器類:Milk和Sugar,它們分別表示加牛奶和加糖的調料:
//milk類
public class Milk extends CondimentDecorator { public Milk(Beverage beverage) { super(beverage); } @Override public String getDescription() { return beverage.getDescription() + ", Milk"; } @Override public double cost() { return beverage.cost() + 0.20; // 假設加牛奶要額外收費0.2美元 }
} //suger類
public class Sugar extends CondimentDecorator { public Sugar(Beverage beverage) { super(beverage); } @Override public String getDescription() { return beverage.getDescription() + ", Sugar"; } @Override public double cost() { return beverage.cost() + 0.10; // 假設加糖要額外收費0.1美元 }
}
最后創建一個客戶端類來演示如何使用裝飾模式:
public class CoffeeShop { public static void main(String[] args) { Beverage beverage = new DarkRoast(); System.out.println(beverage.getDescription() + " $" + beverage.cost()); Beverage beverageWithMilk = new Milk(new DarkRoast()); System.out.println(beverageWithMilk.getDescription() + " $" + beverageWithMilk.cost()); Beverage beverageWithSugarAndMilk = new Milk(new Sugar(new DarkRoast())); System.out.println(beverageWithSugarAndMilk.getDescription() + " $" + beverageWithSugarAndMilk.cost()); }
}
最后運行代碼會顯示:
Dark Roast Coffee $1.99
Dark Roast Coffee, Milk $2.19
Dark Roast Coffee, Sugar, Milk $2.29