装饰器模式概述
装饰器模式是一种结构型设计模式,允许在不修改对象结构的前提下动态扩展功能。该模式通过包装对象实现功能增强,避免了继承带来的局限性。
核心思想
装饰器模式的核心原则包括:
- 动态扩展:运行时灵活添加新功能
- 接口一致:装饰器与被装饰对象保持相同接口
- 组合优先:采用对象组合而非继承实现扩展
- 职责单一:每个装饰器仅关注单一功能扩展
典型结构
1. 抽象组件(Component)
java
public interface Coffee {
String getDescription();
double getCost();
}
2. 具体组件(ConcreteComponent)
java
public class SimpleCoffee implements Coffee {
@Override
public String getDescription() {
return "Simple Coffee";
}
@Override
public double getCost() {
return 2.0;
}
}
3. 抽象装饰器(Decorator)
java
public abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public String getDescription() {
return coffee.getDescription();
}
@Override
public double getCost() {
return coffee.getCost();
}
}
4. 具体装饰器(ConcreteDecorator)
java
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + ", Milk";
}
@Override
public double getCost() {
return coffee.getCost() + 0.5;
}
}
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + ", Sugar";
}
@Override
public double getCost() {
return coffee.getCost() + 0.2;
}
}
public class WhipDecorator extends CoffeeDecorator {
public WhipDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + ", Whip";
}
@Override
public double getCost() {
return coffee.getCost() + 0.7;
}
}
使用示例
java
public class CoffeeShop {
public static void main(String[] args) {
// 基础咖啡
Coffee coffee = new SimpleCoffee();
System.out.println("Cost: " + coffee.getCost() + ", Description: " + coffee.getDescription());
// 添加牛奶
Coffee milkCoffee = new MilkDecorator(coffee);
System.out.println("Cost: " + milkCoffee.getCost() + ", Description: " + milkCoffee.getDescription());
// 添加糖
Coffee sweetMilkCoffee = new SugarDecorator(milkCoffee);
System.out.println("Cost: " + sweetMilkCoffee.getCost() + ", Description: " + sweetMilkCoffee.getDescription());
// 添加奶油
Coffee whippedSweetMilkCoffee = new WhipDecorator(sweetMilkCoffee);
System.out.println("Cost: " + whippedSweetMilkCoffee.getCost() + ", Description: " + whippedSweetMilkCoffee.getDescription());
// 直接创建复杂组合
Coffee complexCoffee = new WhipDecorator(
new SugarDecorator(
new MilkDecorator(
new SimpleCoffee()
)
)
);
System.out.println("Complex Coffee - Cost: " + complexCoffee.getCost() + ", Description: " + complexCoffee.getDescription());
}
}
输出结果
Cost: 2.0, Description: Simple Coffee
Cost: 2.5, Description: Simple Coffee, Milk
Cost: 2.7, Description: Simple Coffee, Milk, Sugar
Cost: 3.4, Description: Simple Coffee, Milk, Sugar, Whip
Complex Coffee - Cost: 3.4, Description: Simple Coffee, Milk, Sugar, Whip
实际应用场景
1. Java IO流
java
// 基础流
InputStream fileStream = new FileInputStream("file.txt");
// 装饰器:缓冲流
InputStream bufferedStream = new BufferedInputStream(fileStream);
// 装饰器:数据流
DataInputStream dataStream = new DataInputStream(bufferedStream);
// 装饰器:压缩流
GZIPInputStream compressedStream = new GZIPInputStream(dataStream);
2. 图形界面组件
public interface Window {
void draw();
String getDescription();
}
public class SimpleWindow implements Window {
@Override
public void draw() {
System.out.println("绘制基础窗口");
}
@Override
public String getDescription() {
return "基础窗口";
}
}
public abstract class WindowDecorator implements Window {
protected Window decoratedWindow;
public WindowDecorator(Window window) {
this.decoratedWindow = window;
}
@Override
public void draw() {
decoratedWindow.draw();
}
@Override
public String getDescription() {
return decoratedWindow.getDescription();
}
}
public class ScrollBarDecorator extends WindowDecorator {
public ScrollBarDecorator(Window window) {
super(window);
}
@Override
public void draw() {
decoratedWindow.draw();
drawScrollBar();
}
private void drawScrollBar() {
System.out.println("绘制滚动条");
}
@Override
public String getDescription() {
return decoratedWindow.getDescription() + "(带滚动条)";
}
}
public class BorderDecorator extends WindowDecorator {
public BorderDecorator(Window window) {
super(window);
}
@Override
public void draw() {
decoratedWindow.draw();
drawBorder();
}
private void drawBorder() {
System.out.println("绘制边框");
}
@Override
public String getDescription() {
return decoratedWindow.getDescription() + "(带边框)";
}
}
装饰器模式的优势
- 灵活性:可以在运行时动态添加或移除功能
- 开闭原则:对扩展开放,对修改关闭
- 单一职责:每个装饰器只负责一个功能
- 组合性:可以任意组合多个装饰器
- 透明性:客户端代码不需要知道装饰器的存在
适用场景
- 动态功能扩展:需要在运行时添加功能
- 避免子类爆炸:当继承会导致大量子类时
- 功能组合:需要灵活组合多个功能
- 现有代码扩展:不想修改现有代码结构
- 责任分离:将不同功能分离到不同装饰器中
与其他模式的区别
- 适配器模式:改变接口,装饰器保持接口不变
- 代理模式:控制访问,装饰器扩展功能
- 组合模式:处理树形结构,装饰器处理链式结构
- 策略模式:替换算法,装饰器添加功能
注意事项
- 过度使用:可能导致大量小类
- 调试困难:多层装饰可能难以调试
- 性能影响:多层装饰可能影响性能
- 设计复杂性:需要仔细设计装饰器层次
最佳实践
- 保持简单:避免创建过于复杂的装饰器层次
- 文档化:清楚记录装饰器的功能和使用方式
- 测试:充分测试装饰器的组合效果
- 命名规范:使用清晰的命名约定
装饰器模式是Java中非常实用的设计模式,特别适合需要动态扩展功能的场景,如Java IO流、图形界面组件等。它提供了一种灵活而强大的方式来扩展对象功能,是现代软件开发中不可或缺的设计模式之一。