Skip to content

装饰器模式 (Decorator Pattern) ​

模式定义 ​

装饰器模式是一种结构型设计模式,它动态地给对象添加额外职责,比继承更灵活。装饰器提供了比继承更有弹性的替代方案。

核心要点 ​

  • 装饰器和被装饰对象实现相同接口
  • 装饰器持有被装饰对象的引用
  • 可以动态添加功能

实现示例:咖啡店 ​

组件接口 ​

java
// 饮品接口
public interface Beverage {
    String getDescription();
    double getCost();
}

// 调料接口(装饰器接口)
public interface CondimentDecorator extends Beverage {
    // 扩展饮料,添加调料
}

基础组件 ​

java
// 浓缩咖啡
public class Espresso implements Beverage {
    @Override
    public String getDescription() {
        return "浓缩咖啡";
    }

    @Override
    public double getCost() {
        return 15.0;
    }
}

// 深烘焙咖啡
public class DarkRoast implements Beverage {
    @Override
    public String getDescription() {
        return "深烘焙咖啡";
    }

    @Override
    public double getCost() {
        return 12.0;
    }
}

// 综合咖啡
public class HouseBlend implements Beverage {
    @Override
    public String getDescription() {
        return "综合咖啡";
    }

    @Override
    public double getCost() {
        return 10.0;
    }
}

装饰器(调料) ​

java
// 调料装饰器抽象类
public abstract class CondimentDecorator implements CondimentDecorator {
    protected final Beverage beverage;

    public CondimentDecorator(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription();
    }

    @Override
    public double getCost() {
        return beverage.getCost();
    }
}

// 牛奶装饰器
public class Milk extends CondimentDecorator {
    public Milk(Beverage beverage) {
        super(beverage);
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + " + 牛奶";
    }

    @Override
    public double getCost() {
        return beverage.getCost() + 3.0;
    }
}

// 摩卡装饰器
public class Mocha extends CondimentDecorator {
    public Mocha(Beverage beverage) {
        super(beverage);
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + " + 摩卡";
    }

    @Override
    public double getCost() {
        return beverage.getCost() + 5.0;
    }
}

// 奶泡装饰器
public class Whip extends CondimentDecorator {
    public Whip(Beverage beverage) {
        super(beverage);
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + " + 奶泡";
    }

    @Override
    public double getCost() {
        return beverage.getCost() + 2.0;
    }
}

// 焦糖装饰器
public class Caramel extends CondimentDecorator {
    public Caramel(Beverage beverage) {
        super(beverage);
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + " + 焦糖";
    }

    @Override
    public double getCost() {
        return beverage.getCost() + 4.0;
    }
}

使用示例 ​

java
public class CoffeeShopDemo {
    public static void main(String[] args) {
        // 1. 浓缩咖啡
        Beverage beverage1 = new Espresso();
        System.out.println(beverage1.getDescription() + " ¥" + beverage1.getCost());

        // 2. 深烘焙 + 摩卡 + 奶泡
        Beverage beverage2 = new DarkRoast();
        beverage2 = new Mocha(beverage2);
        beverage2 = new Mocha(beverage2); // 双份摩卡
        beverage2 = new Whip(beverage2);
        System.out.println(beverage2.getDescription() + " ¥" + beverage2.getCost());

        // 3. 综合 + 牛奶 + 焦糖 + 奶泡
        Beverage beverage3 = new HouseBlend();
        beverage3 = new Milk(beverage3);
        beverage3 = new Caramel(beverage3);
        beverage3 = new Whip(beverage3);
        System.out.println(beverage3.getDescription() + " ¥" + beverage3.getCost());
    }
}

输出:

浓缩咖啡 ¥15.0
深烘焙咖啡 + 摩卡 + 摩卡 + 奶泡 ¥24.0
综合咖啡 + 牛奶 + 焦糖 + 奶泡 ¥19.0

Java IO 中的装饰器模式 ​

Java I/O 流就是典型的装饰器模式应用。

java
public class JavaIODecoratorDemo {
    public static void main(String[] args) throws IOException {
        // 基础流
        InputStream is = new FileInputStream("test.txt");

        // 装饰:添加缓冲功能
        InputStream bis = new BufferedInputStream(is);

        // 装饰:添加行号功能
        LineNumberReader reader = new LineNumberReader(
                new BufferedReader(
                        new InputStreamReader(
                                new FileInputStream("test.txt"), "UTF-8")));

        // 读取内容
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(reader.getLineNumber() + ": " + line);
        }

        // 经典的 IO 装饰器链
        // new BufferedReader(
        //     new InputStreamReader(
        //         new FileInputStream("file.txt"), "UTF-8"))
    }
}

IO 装饰器层次结构 ​

InputStream (抽象组件)
├── FileInputStream (具体组件)
├── ByteArrayInputStream (具体组件)
├── FilterInputStream (装饰器基类)
│   ├── BufferedInputStream (具体装饰器)
│   ├── DataInputStream (具体装饰器)
│   └── PushbackInputStream (具体装饰器)

统计装饰器示例 ​

在不修改原有类的情况下,添加性能统计功能。

java
// 数据访问接口
public interface DataService {
    String queryData(String key);
    void saveData(String key, String value);
}

// 具体实现
public class DatabaseDataService implements DataService {
    @Override
    public String queryData(String key) {
        // 模拟数据库查询
        return "value_" + key;
    }

    @Override
    public void saveData(String key, String value) {
        // 模拟数据库保存
        System.out.println("保存数据: " + key + " = " + value);
    }
}

// 性能统计装饰器
public class PerformanceDecorator implements DataService {
    private final DataService delegate;

    public PerformanceDecorator(DataService delegate) {
        this.delegate = delegate;
    }

    @Override
    public String queryData(String key) {
        long start = System.currentTimeMillis();
        String result = delegate.queryData(key);
        long end = System.currentTimeMillis();
        System.out.println("查询耗时: " + (end - start) + "ms, key=" + key);
        return result;
    }

    @Override
    public void saveData(String key, String value) {
        long start = System.currentTimeMillis();
        delegate.saveData(key, value);
        long end = System.currentTimeMillis();
        System.out.println("保存耗时: " + (end - start) + "ms");
    }
}

// 日志装饰器
public class LoggingDecorator implements DataService {
    private final DataService delegate;

    public LoggingDecorator(DataService delegate) {
        this.delegate = delegate;
    }

    @Override
    public String queryData(String key) {
        System.out.println("[LOG] 查询数据: " + key);
        String result = delegate.queryData(key);
        System.out.println("[LOG] 查询结果: " + result);
        return result;
    }

    @Override
    public void saveData(String key, String value) {
        System.out.println("[LOG] 保存数据: " + key + " = " + value);
        delegate.saveData(key, value);
        System.out.println("[LOG] 保存完成");
    }
}

// 使用
public class DecoratorDemo {
    public static void main(String[] args) {
        // 组合装饰器
        DataService service = new PerformanceDecorator(
                new LoggingDecorator(
                        new DatabaseDataService()));

        service.queryData("user_1");
        System.out.println("---");
        service.saveData("user_2", "张三");
    }
}

装饰器 vs 继承 vs 代理 ​

特性装饰器继承代理
功能扩展动态静态动态
运行时行为可变固定可变
目的增强功能扩展功能控制访问
组合方式可多层装饰单继承一对一

优缺点 ​

优点:

  • 比继承更灵活,可以动态添加功能
  • 符合开闭原则,不修改原有代码
  • 可以自由组合功能
  • 比继承更细粒度的控制

缺点:

  • 会产生很多小类,增加复杂度
  • 多层装饰时,调试困难
  • 移除装饰器需要修改客户端代码

适用场景 ​

  • 需要动态、透明地给对象添加职责
  • 不可以通过继承扩展功能时
  • Java I/O 流的设计
  • 日志、安全、事务等横切关注点