以下是 装饰器模式 (Decorator Pattern) 的详细介绍,包含定义、优缺点、应用场景及代码实现:
一、装饰器模式概述
-
英文名称:Decorator
-
核心目标:动态地为对象添加额外的职责,且不改变其原有结构,提供比继承更灵活的扩展方式。
-
设计思想:通过包装对象(即装饰器)增强功能,形成链式调用结构,支持功能的组合叠加。
二、优缺点
优点:
-
灵活扩展:运行时动态添加或撤销功能,避免继承导致的类爆炸。
-
符合开闭原则:新增装饰器无需修改原有代码。
-
组合优于继承:通过多层装饰实现复杂功能叠加。
缺点:
-
代码复杂度增加:需管理多个装饰器类及调用顺序。
-
调试困难:多层装饰可能使调试链路变长。
三、应用场景
-
Java I/O 流:如
BufferedInputStream
包装FileInputStream
。 -
GUI 组件:动态为按钮、窗口添加边框、滚动条等。
-
中间件增强:为 HTTP 请求添加日志、缓存、鉴权等处理层。
-
游戏角色装备:动态叠加武器、护甲等装备效果。
四、代码实现与注释
以下通过 咖啡订单系统 的案例演示装饰器模式:
1. 抽象组件(咖啡接口)
/**
* 抽象组件:定义咖啡的基本接口
*/
public interface Coffee {
// 获取咖啡描述
String getDescription();
// 计算价格
double getCost();
}
2. 具体组件(基础咖啡类型)
/**
* 具体组件:浓缩咖啡(基础咖啡)
*/
public class Espresso implements Coffee {
@Override
public String getDescription() {
return "浓缩咖啡";
}
@Override
public double getCost() {
return 2.0; // 基础价格 2 元
}
}
/**
* 具体组件:深焙咖啡(基础咖啡)
*/
public class DarkRoast implements Coffee {
@Override
public String getDescription() {
return "深焙咖啡";
}
@Override
public double getCost() {
return 2.5;
}
}
3. 抽象装饰器(调料基类)
/**
* 抽象装饰器:持有咖啡对象的引用,并实现 Coffee 接口
*/
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 getCost() {
return decoratedCoffee.getCost();
}
}
4. 具体装饰器(调料实现)
/**
* 具体装饰器:牛奶(添加牛奶调料)
*/
public class Milk extends CoffeeDecorator {
public Milk(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return super.getDescription() + " + 牛奶";
}
@Override
public double getCost() {
return super.getCost() + 0.5; // 牛奶价格 +0.5 元
}
}
/**
* 具体装饰器:糖(添加糖调料)
*/
public class Sugar extends CoffeeDecorator {
public Sugar(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return super.getDescription() + " + 糖";
}
@Override
public double getCost() {
return super.getCost() + 0.3; // 糖价格 +0.3 元
}
}
5. 客户端调用
public class Client {
public static void main(String[] args) {
// 基础浓缩咖啡
Coffee espresso = new Espresso();
System.out.println(espresso.getDescription() + " 价格:" + espresso.getCost());
// 为浓缩咖啡添加牛奶和糖
Coffee decoratedCoffee = new Milk(espresso);
decoratedCoffee = new Sugar(decoratedCoffee);
System.out.println(decoratedCoffee.getDescription() + " 价格:" + decoratedCoffee.getCost());
// 深焙咖啡 + 双倍糖
Coffee darkRoast = new DarkRoast();
darkRoast = new Sugar(darkRoast);
darkRoast = new Sugar(darkRoast);
System.out.println(darkRoast.getDescription() + " 价格:" + darkRoast.getCost());
}
}
6. 输出结果
浓缩咖啡 价格:2.0
浓缩咖啡 + 牛奶 + 糖 价格:2.8
深焙咖啡 + 糖 + 糖 价格:3.1
五、模式结构图
+----------------+ +----------------+
| Component | <------+ | Decorator |
+----------------+ +----------------+
| +operation() | | -component:Component|
+----------------+ | +operation() |
^ +----------------+
| ^
| |
+----------------+ +----------------+
| ConcreteComponent | ConcreteDecorator|
+----------------+ +----------------+
| +operation() | | +operation() |
+----------------+ +----------------+
六、与其他模式的关系
-
适配器模式:装饰器增强对象功能,适配器改变接口。
-
组合模式:装饰器可视为只有一个组件的组合结构。
-
策略模式:装饰器动态改变对象行为,策略模式静态切换算法。
七、最佳实践
-
保持接口一致性:装饰器必须与组件接口一致,确保透明性。
-
控制装饰层数:避免过度装饰导致性能下降和代码混乱。
-
使用工厂模式:通过工厂管理装饰器的创建和组合逻辑。
八、总结
-
核心价值:动态扩展对象功能,避免继承带来的静态局限性。
-
适用场景:需灵活叠加功能的系统,如中间件、UI组件、I/O流处理。
-
关键实现:组件接口 + 具体组件 + 抽象装饰器 + 具体装饰器。
装饰器模式在 Java 标准库中广泛应用,如 java.io.InputStream
的装饰器类(BufferedInputStream
、DataInputStream
)。掌握该模式可显著提升代码的扩展性和复用性。