一、模式定義
裝飾者模式屬於結構型設計模式,允許通過動態包裝對象的方式為對象添加新功能,提供比繼承更靈活的擴展方式。該模式通過組合替代繼承,遵循開閉原則(對擴展開放,對修改關閉)。
二、核心角色
-
Component(組件接口)
- 定義被裝飾對象的公共接口
-
ConcreteComponent(具體組件)
- 實現基礎功能的具體類
-
Decorator(裝飾者基類)
- 持有Component引用,實現Component接口
-
ConcreteDecorator(具體裝飾者)
- 添加具體裝飾功能的實現類
三、經典實現(咖啡店訂單系統)
// 1. 組件接口
public interface Coffee {
String getDescription();
double cost();
}
// 2. 具體組件
public class SimpleCoffee implements Coffee {
@Override
public String getDescription() {
return "Simple Coffee";
}
@Override
public double cost() {
return 1.0;
}
}
// 3. 裝飾者基類
public abstract class CoffeeDecorator implements Coffee {
protected final Coffee decoratedCoffee;
public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
@Override
public String getDescription() {
return decoratedCoffee.getDescription();
}
@Override
public double cost() {
return decoratedCoffee.cost();
}
}
// 4. 具體裝飾者
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return super.getDescription() + ", Milk";
}
@Override
public double cost() {
return super.cost() + 0.5;
}
}
public class MochaDecorator extends CoffeeDecorator {
public MochaDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return super.getDescription() + ", Mocha";
}
@Override
public double cost() {
return super.cost() + 0.7;
}
}
// 5. 客户端使用
public class CoffeeShop {
public static void main(String[] args) {
Coffee order = new SimpleCoffee();
System.out.println(order.getDescription() + " $" + order.cost());
order = new MilkDecorator(order);
System.out.println(order.getDescription() + " $" + order.cost());
order = new MochaDecorator(order);
System.out.println(order.getDescription() + " $" + order.cost());
}
}
四、模式結構UML
_________________________
| Component |
|-------------------------|
| + getDescription() |
| + cost() |
|_________________________|
▲
___________|___________
| |
_________▼_________ ______▼_______
| ConcreteComponent | | Decorator |
|-------------------| |--------------|
| + getDescription()| | - component |
| + cost() | |______________|
|___________________| ▲
_________|_________
| |
_______▼_______ _______▼_______
| ConcreteDecoratorA | | ConcreteDecoratorB |
|--------------------| |--------------------|
| + addedBehavior() | | + addedBehavior() |
|____________________| |____________________|
五、模式優劣分析
優勢:
- 動態擴展功能,比繼承更靈活
- 符合開閉原則,無需修改現有代碼
- 支持多層嵌套裝飾
- 不同裝飾類可自由組合
劣勢:
- 多層裝飾增加代碼複雜度
- 裝飾順序影響最終結果
- 可能產生大量小類
- 調試困難(需逐層檢查裝飾)
六、應用場景
- 動態擴展對象功能
(如為圖形界面組件添加邊框、滾動條) - 撤銷功能實現
(通過裝飾記錄操作歷史) - 數據流處理
(Java I/O中的緩衝、加密處理) - 權限控制
(通過裝飾添加權限校驗層) - 日誌記錄
(為業務邏輯添加日誌裝飾)
七、Java標準庫應用
Java I/O流典型實現:
// 多層裝飾示例
InputStream in = new FileInputStream("data.txt");
in = new BufferedInputStream(in); // 添加緩衝功能
in = new GZIPInputStream(in); // 添加解壓縮功能
in = new Base64InputStream(in); // 添加Base64解碼
// 自定義裝飾者示例
class UppercaseInputStream extends FilterInputStream {
public UppercaseInputStream(InputStream in) {
super(in);
}
@Override
public int read() throws IOException {
int c = super.read();
return (c == -1) ? c : Character.toUpperCase(c);
}
}
八、高級應用技巧
透明性控制
通過接口繼承保持裝飾透明性:
interface Window {
void draw();
}
class BasicWindow implements Window { /*...*/ }
abstract class WindowDecorator implements Window {
protected Window window;
// 不暴露額外方法
}
裝飾順序控制
使用建造者模式管理裝飾順序:
public class CoffeeBuilder {
private Coffee coffee = new SimpleCoffee();
public CoffeeBuilder addMilk() {
coffee = new MilkDecorator(coffee);
return this;
}
public Coffee build() {
return coffee;
}
}
動態移除裝飾
實現裝飾棧管理:
public class UndoableCoffee implements Coffee {
private Deque<Coffee> stack = new ArrayDeque<>();
public UndoableCoffee(Coffee coffee) {
stack.push(coffee);
}
public void addDecorator(CoffeeDecorator decorator) {
stack.push(decorator);
}
public void undo() {
if (stack.size() > 1) {
stack.pop();
}
}
// 實現Coffee接口方法...
}
九、最佳實踐建議
- 保持組件接口簡潔
避免裝飾者需要實現過多無關方法 - 控制裝飾層次深度
建議不超過4層裝飾 - 優先使用透明裝飾
保持裝飾前後接口一致 - 注意線程安全問題
對於可變狀態裝飾器,使用同步控制 - 性能敏感場景慎用
多層裝飾可能影響性能(建議結合對象池)