装饰器模式 (Decorator Pattern)
什么是装饰器模式?
装饰器模式是一种结构型设计模式,它允许你在不改变对象结构的情况下动态地给对象添加新的功能。
简单来说:装饰器模式就是给对象"穿衣服",可以一层一层地添加功能。
生活中的例子
想象一下:
- 穿衣服:先穿内衣,再穿衬衫,再穿外套,最后穿大衣
- 装饰蛋糕:先做蛋糕,再涂奶油,再放水果,最后放蜡烛
- 装修房子:先刷墙,再铺地板,再买家具,最后挂画
为什么需要装饰器模式?
传统方式的问题
java
// 使用继承会导致类爆炸
class SimpleCoffee {}
class MilkCoffee extends SimpleCoffee {}
class SugarCoffee extends SimpleCoffee {}
class MilkSugarCoffee extends SimpleCoffee {}
// ... 更多组合
问题:
- 类爆炸:多个功能组合会导致类数量爆炸
- 扩展困难:新增功能需要创建多个类
- 灵活性差:无法动态添加或移除功能
装饰器模式的优势
java
// 动态添加功能
Coffee coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
优势:
- 动态添加:可以动态地添加或移除功能
- 灵活组合:可以灵活地组合多个功能
- 避免类爆炸:避免因继承导致的类爆炸
装饰器模式的结构
┌─────────────────────┐
│ Component │ 组件接口
├─────────────────────┤
│ + operation(): void │
└──────────┬──────────┘
│ 实现
├──┬──────────────────┬──────────────┐
│ │ │
┌──────────┴──────┐ ┌───────────┴───────┐ ┌───┴────────┐
│ ConcreteComp │ │ Decorator │ │ ... │
├─────────────────┤ ├───────────────────┤ ├────────────┤
│ + operation() │ │ - component: Comp │ │ │
└─────────────────┘ │ + operation() │ │ │
└──────────┬────────┘ │ │
│ 实现 │ │
┌───────────┴────────┐ │ │
│ ConcreteDecorator │ │ │
├───────────────────┤ │ │
│ + operation() │ │ │
└───────────────────┘ └────────────┘
代码示例
1. 定义组件接口
java
/**
* 咖啡接口
*/
public interface Coffee {
/**
* 计算价格
*/
double cost();
/**
* 获取描述
*/
String description();
}
2. 定义具体组件
java
/**
* 具体组件:简单咖啡
*/
public class SimpleCoffee implements Coffee {
@Override
public double cost() {
return 10.0;
}
@Override
public String description() {
return "简单咖啡";
}
}
3. 定义装饰器
java
/**
* 抽象装饰器:咖啡装饰器
*/
public abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public double cost() {
return coffee.cost();
}
@Override
public String description() {
return coffee.description();
}
}
4. 定义具体装饰器
java
/**
* 具体装饰器:牛奶
*/
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return coffee.cost() + 2.0;
}
@Override
public String description() {
return coffee.description() + " + 牛奶";
}
}
/**
* 具体装饰器:糖
*/
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return coffee.cost() + 1.0;
}
@Override
public String description() {
return coffee.description() + " + 糖";
}
}
/**
* 具体装饰器:奶油
*/
public class WhipDecorator extends CoffeeDecorator {
public WhipDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return coffee.cost() + 3.0;
}
@Override
public String description() {
return coffee.description() + " + 奶油";
}
}
5. 使用装饰器
java
/**
* 装饰器模式测试类
* 演示如何使用装饰器模式动态地给对象添加功能
*/
public class DecoratorTest {
public static void main(String[] args) {
System.out.println("=== 装饰器模式测试 ===\n");
// 创建简单咖啡
Coffee coffee = new SimpleCoffee();
System.out.println(coffee.description() + ": ¥" + coffee.cost());
// 添加牛奶
coffee = new MilkDecorator(coffee);
System.out.println(coffee.description() + ": ¥" + coffee.cost());
// 添加糖
coffee = new SugarDecorator(coffee);
System.out.println(coffee.description() + ": ¥" + coffee.cost());
// 添加奶油
coffee = new WhipDecorator(coffee);
System.out.println(coffee.description() + ": ¥" + coffee.cost());
System.out.println("\n--- 创建不同的组合 ---");
// 只加牛奶和糖
Coffee coffee1 = new MilkDecorator(new SugarDecorator(new SimpleCoffee()));
System.out.println(coffee1.description() + ": ¥" + coffee1.cost());
// 只加奶油
Coffee coffee2 = new WhipDecorator(new SimpleCoffee());
System.out.println(coffee2.description() + ": ¥" + coffee2.cost());
// 全部添加
Coffee coffee3 = new WhipDecorator(new SugarDecorator(new MilkDecorator(new SimpleCoffee())));
System.out.println(coffee3.description() + ": ¥" + coffee3.cost());
System.out.println("\n=== 装饰器模式的优势 ===");
System.out.println("1. 动态添加:可以动态地添加或移除功能");
System.out.println("2. 灵活组合:可以灵活地组合多个功能");
System.out.println("3. 避免类爆炸:避免因继承导致的类爆炸");
System.out.println("4. 单一职责:每个装饰器只负责一个功能");
System.out.println("\n=== 实际应用场景 ===");
System.out.println("1. IO流:Java IO流中的BufferedReader、LineNumberReader等");
System.out.println("2. UI组件:给按钮添加边框、滚动条等");
System.out.println("3. 日志记录:给日志添加时间戳、级别等");
System.out.println("4. 数据处理:给数据添加压缩、加密等功能");
}
}
装饰器模式的优点
- 动态添加:可以动态地添加或移除功能
- 灵活组合:可以灵活地组合多个功能
- 避免类爆炸:避免因继承导致的类爆炸
- 单一职责:每个装饰器只负责一个功能
装饰器模式的缺点
- 增加复杂度:引入了多个小类
- 调试困难:多层装饰会导致调试困难
适用场景
- 动态添加功能:需要动态地添加或移除功能
- 功能组合:需要灵活地组合多个功能
- 避免类爆炸:需要避免因继承导致的类爆炸
常见应用场景
- IO流:Java IO流中的BufferedReader、LineNumberReader等
- UI组件:给按钮添加边框、滚动条等
- 日志记录:给日志添加时间戳、级别等
使用建议
- 动态添加功能:使用装饰器模式
- 功能组合:使用装饰器模式
- 固定功能:直接使用继承即可
注意事项
⚠️ 装饰器模式虽然强大,但要注意:
- 不要过度装饰,增加不必要的复杂度
- 保持装饰器的顺序性