Java 设计模式:装饰者模式(Decorator Pattern)

时间:2025-03-14 15:52:40

一、模式定义

装饰者模式属于结构型设计模式,允许通过动态包装对象的方式为对象添加新功能,提供比继承更灵活的扩展方式。该模式通过组合替代继承,遵循开闭原则(对扩展开放,对修改关闭)。

二、核心角色

  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. 性能敏感场景慎用
    多层装饰可能影响性能(建议结合对象池)