装饰器模式(Decorator Pattern)
装饰器模式 是 结构型设计模式 之一,它允许你动态地给对象添加新的功能,而无需修改其原始代码。装饰器模式通常用于扩展类的功能,而不使用继承。
1. 装饰器模式的核心思想
• 继承 vs. 装饰器模式
• 继承:创建子类来扩展功能,但可能会导致子类膨胀(类爆炸问题)。
• 装饰器模式:使用对象组合(composition),在运行时动态添加行为,比继承更加灵活。
• 关键点
1. 装饰器(Decorator)和被装饰的对象(Component)必须有相同的接口,这样装饰器就可以替换原始对象。
2. 装饰器持有一个被装饰对象的引用,并在调用方法时增强原有功能。
2. 代码示例(Java 实现)
假设我们有一个 Coffee 接口,表示一杯咖啡,我们想要动态地添加牛奶、糖等配料,而不直接修改 Coffee 类。
(1)定义组件接口
// 抽象组件
public interface Coffee {
String getDescription(); // 获取描述
double cost(); // 计算价格
}
(2)实现基础组件
// 具体组件:普通咖啡
public class SimpleCoffee implements Coffee {
@Override
public String getDescription() {
return "普通咖啡";
}
@Override
public double cost() {
return 10.0; // 普通咖啡价格
}
}
(3)创建抽象装饰器
// 抽象装饰器
public abstract class CoffeeDecorator implements Coffee {
protected 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() + " + 牛奶";
}
@Override
public double cost() {
return super.cost() + 3.0; // 牛奶价格
}
}
// 具体装饰器:加糖
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return super.getDescription() + " + 糖";
}
@Override
public double cost() {
return super.cost() + 2.0; // 糖的价格
}
}
(5)测试装饰器模式
public class DecoratorPatternTest {
public static void main(String[] args) {
Coffee coffee = new SimpleCoffee();
System.out.println(coffee.getDescription() + " 价格:" + coffee.cost());
// 加牛奶
coffee = new MilkDecorator(coffee);
System.out.println(coffee.getDescription() + " 价格:" + coffee.cost());
// 加糖
coffee = new SugarDecorator(coffee);
System.out.println(coffee.getDescription() + " 价格:" + coffee.cost());
}
}
(6)运行结果
普通咖啡 价格:10.0
普通咖啡 + 牛奶 价格:13.0
普通咖啡 + 牛奶 + 糖 价格:15.0
✅ 装饰器模式让我们在不修改 Coffee 类的情况下,动态地增加功能!
3. 装饰器模式 vs. 继承
|
对比项 |
继承 |
装饰器模式 |
|---|---|---|
|
扩展方式 |
通过子类扩展 |
通过组合对象 |
|
灵活性 |
需要创建多个子类 |
运行时动态组合多个装饰器 |
|
类膨胀问题 |
过多子类可能导致类爆炸 |
解决类膨胀问题 |
|
适用于 |
静态扩展(编译时确定) |
运行时动态扩展 |
4. Spring 框架中的应用
Spring 使用装饰器模式的地方很多,比如:
• HttpServletRequestWrapper / HttpServletResponseWrapper:用于包装 HTTP 请求和响应,增强其功能。
• Spring AOP(Aspect-Oriented Programming):用于动态代理,在方法调用前后插入增强逻辑,比如日志记录、事务管理等。
• Spring Security:用于动态添加安全检查,比如权限认证、CSRF 保护等。
5. 总结
• 装饰器模式用于动态扩展对象功能,而不修改原有类。
• 相比继承,装饰器模式更加灵活,可组合多个功能。
• 在 Java、Spring、设计模式中,装饰器模式被广泛使用。
浙公网安备 33010602011771号