动态

详情 返回 返回

Java 設計模式:裝飾者模式(Decorator Pattern)

一、模式定義

裝飾者模式屬於結構型設計模式,允許通過動態包裝對象的方式為對象添加新功能,提供比繼承更靈活的擴展方式。該模式通過組合替代繼承,遵循開閉原則(對擴展開放,對修改關閉)。

二、核心角色

  1. Component(組件接口)

    • 定義被裝飾對象的公共接口
  2. ConcreteComponent(具體組件)

    • 實現基礎功能的具體類
  3. Decorator(裝飾者基類)

    • 持有Component引用,實現Component接口
  4. 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()  |
                  |____________________|   |____________________|

五、模式優劣分析

優勢:

  • 動態擴展功能,比繼承更靈活
  • 符合開閉原則,無需修改現有代碼
  • 支持多層嵌套裝飾
  • 不同裝飾類可自由組合

劣勢:

  • 多層裝飾增加代碼複雜度
  • 裝飾順序影響最終結果
  • 可能產生大量小類
  • 調試困難(需逐層檢查裝飾)

六、應用場景

  1. 動態擴展對象功能
    (如為圖形界面組件添加邊框、滾動條)
  2. 撤銷功能實現
    (通過裝飾記錄操作歷史)
  3. 數據流處理
    (Java I/O中的緩衝、加密處理)
  4. 權限控制
    (通過裝飾添加權限校驗層)
  5. 日誌記錄
    (為業務邏輯添加日誌裝飾)

七、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接口方法...
}

九、最佳實踐建議

  1. 保持組件接口簡潔
    避免裝飾者需要實現過多無關方法
  2. 控制裝飾層次深度
    建議不超過4層裝飾
  3. 優先使用透明裝飾
    保持裝飾前後接口一致
  4. 注意線程安全問題
    對於可變狀態裝飾器,使用同步控制
  5. 性能敏感場景慎用
    多層裝飾可能影響性能(建議結合對象池)
user avatar
0 用户, 点赞了这篇动态!

发布 评论

Some HTML is okay.