3Head First Design Patterns(第2版)

装饰者模式

动态扩展

装饰者模式开放-关闭原则组合扩展包装对象

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第3章:装饰者模式(Decorator Pattern)

一、导读

1.1 本章学习目标

第3章讲解装饰者模式——一种动态地给对象添加额外职责的设计模式。相比继承,装饰者提供了更灵活的功能扩展方式。

1.2 为什么第三章如此重要

装饰者模式体现了"开放-关闭原则"——对扩展开放,对修改关闭。它是替代继承的有力工具,在 Java I/O、GUI 组件等场景中广泛应用。

1.3 核心问题引导

装饰者模式如何替代继承来扩展功能?

装饰者和被装饰对象有什么关系?

如何避免装饰者层次过深?

装饰者模式在 Java I/O 中如何应用?


二、核心概念详解

2.1 装饰者模式的结构

┌────────────────┐
│  <<interface>>  │
│   Component    │
│────────────────│
│ + operation()  │
└────────────────┘
      ▲
      │
┌─────┴──────┐  ┌────────────────┐
│ Concrete    │  │  <<abstract>>   │
│ Component   │  │   Decorator    │
│─────────────│  │────────────────│
│+ operation()│  │ - component    │
└─────────────┘  │────────────────│
                 │ + operation()  │
                 └────────────────┘
                       ▲
                 ┌─────┴──────┐
                 │ Concrete    │
                 │ Decorator   │
                 │─────────────│
                 │+ operation()│
                 │ + addedBehavior()│
                 └─────────────┘

2.2 实现

java
// 组件接口
public abstract class Beverage {
    String description = "Unknown Beverage";
    
    public String getDescription() { return description; }
    public abstract double cost();
}

// 装饰者基类
public abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}

// 具体组件
public class Espresso extends Beverage {
    public Espresso() { description = "Espresso"; }
    public double cost() { return 1.99; }
}

public class HouseBlend extends Beverage {
    public HouseBlend() { description = "House Blend Coffee"; }
    public double cost() { return 0.89; }
}

// 具体装饰者
public class Mocha extends CondimentDecorator {
    Beverage beverage;
    
    public Mocha(Beverage beverage) { this.beverage = beverage; }
    
    public String getDescription() {
        return beverage.getDescription() + ", Mocha";
    }
    
    public double cost() { return 0.20 + beverage.cost(); }
}

public class Whip extends CondimentDecorator {
    Beverage beverage;
    
    public Whip(Beverage beverage) { this.beverage = beverage; }
    
    public String getDescription() {
        return beverage.getDescription() + ", Whip";
    }
    
    public double cost() { return 0.10 + beverage.cost(); }
}

// 使用
Beverage beverage = new Espresso();
beverage = new Mocha(beverage);
beverage = new Whip(beverage);
System.out.println(beverage.getDescription() + " $" + beverage.cost());
// Espresso, Mocha, Whip $2.29

2.3 开放-关闭原则

装饰者模式完美体现了开放-关闭原则:

  • 对扩展开放:可以添加新的装饰者来增加新功能。
  • 对修改关闭:不需要修改现有代码。

三、实战案例

3.1 Java I/O 中的装饰者

java
// Java I/O 大量使用装饰者模式
InputStream in = new FileInputStream("file.txt");          // 基础组件
in = new BufferedInputStream(in);                           // 装饰者:缓冲
in = new DataInputStream(in);                               // 装饰者:数据读取

// 可以动态组合不同的装饰者
InputStream in2 = new FileInputStream("file.txt");
in2 = new GZIPInputStream(in2);                             // 装饰者:解压缩
in2 = new BufferedInputStream(in2);                         // 装饰者:缓冲

四、本章小结

装饰者模式通过组合而非继承来扩展功能,体现了开放-关闭原则。Java I/O 是装饰者模式的经典应用。


五、思考与练习

装饰者模式和适配器模式有什么区别?

装饰者层次过深会有什么问题?

如何用装饰者模式实现日志功能?

Java I/O 中还有哪些装饰者的例子?

装饰者模式对性能有什么影响?


3/12装饰者模
0%