装饰器模式详解
一、装饰器模式概述
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
核心特点
- 动态扩展:运行时添加或撤销功能
- 透明装饰:装饰后的对象与原始对象接口一致
- 替代继承:通过组合而非继承扩展功能
- 灵活组合:可以嵌套多个装饰器
二、装饰器模式的结构
主要角色
- Component:抽象组件,定义被装饰对象的接口
- ConcreteComponent:具体组件,实现抽象组件接口
- Decorator:抽象装饰器,继承/实现Component并持有Component引用
- ConcreteDecorator:具体装饰器,实现附加功能
三、装饰器模式的实现
1. 基本实现
// 抽象组件
public interface Coffee {
double getCost();
String getDescription();
}
// 具体组件
public class SimpleCoffee implements Coffee {
public double getCost() {
return 1.0;
}
public String getDescription() {
return "普通咖啡";
}
}
// 抽象装饰器
public abstract class CoffeeDecorator implements Coffee {
protected final Coffee decoratedCoffee;
public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
public double getCost() {
return decoratedCoffee.getCost();
}
public String getDescription() {
return decoratedCoffee.getDescription();
}
}
// 具体装饰器 - 牛奶
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
public double getCost() {
return super.getCost() + 0.5;
}
public String getDescription() {
return super.getDescription() + ", 加牛奶";
}
}
// 具体装饰器 - 糖
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
public double getCost() {
return super.getCost() + 0.2;
}
public String getDescription() {
return super.getDescription() + ", 加糖";
}
}
// 使用示例
Coffee coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
System.out.println("费用: " + coffee.getCost());
System.out.println("描述: " + coffee.getDescription());
2. IO流中的装饰器模式
// 模拟InputStream
public abstract class InputStream {
public abstract int read();
public abstract void close();
}
// 模拟FileInputStream
public class FileInputStream extends InputStream {
public int read() {
System.out.println("读取文件数据");
return 0;
}
public void close() {
System.out.println("关闭文件流");
}
}
// 模拟BufferedInputStream
public class BufferedInputStream extends InputStream {
private InputStream in;
public BufferedInputStream(InputStream in) {
this.in = in;
}
public int read() {
System.out.println("缓冲读取");
return in.read();
}
public void close() {
in.close();
}
}
四、装饰器模式的应用场景
1. Java I/O流体系
// 实际Java IO示例
InputStream in = new FileInputStream("data.txt");
in = new BufferedInputStream(in);
in = new DataInputStream(in);
2. Web请求处理
// HTTP请求处理器接口
public interface HttpRequestHandler {
void handle(HttpRequest request);
}
// 基础处理器
public class BasicHandler implements HttpRequestHandler {
public void handle(HttpRequest request) {
System.out.println("处理基本请求");
}
}
// 认证装饰器
public class AuthenticationDecorator implements HttpRequestHandler {
private HttpRequestHandler handler;
public AuthenticationDecorator(HttpRequestHandler handler) {
this.handler = handler;
}
public void handle(HttpRequest request) {
if (authenticate(request)) {
handler.handle(request);
} else {
throw new SecurityException("认证失败");
}
}
private boolean authenticate(HttpRequest request) {
// 认证逻辑
return true;
}
}
// 日志装饰器
public class LoggingDecorator implements HttpRequestHandler {
private HttpRequestHandler handler;
public LoggingDecorator(HttpRequestHandler handler) {
this.handler = handler;
}
public void handle(HttpRequest request) {
System.out.println("开始处理请求: " + request.getUrl());
handler.handle(request);
System.out.println("请求处理完成");
}
}
3. 图形界面组件
// GUI组件接口
public interface VisualComponent {
void draw();
void resize();
}
// 基础文本框
public class TextView implements VisualComponent {
public void draw() {
System.out.println("绘制文本框");
}
public void resize() {
System.out.println("调整文本框大小");
}
}
// 边框装饰器
public class BorderDecorator implements VisualComponent {
private VisualComponent component;
private int borderWidth;
public BorderDecorator(VisualComponent component, int width) {
this.component = component;
this.borderWidth = width;
}
public void draw() {
component.draw();
drawBorder();
}
public void resize() {
component.resize();
}
private void drawBorder() {
System.out.println("绘制边框,宽度: " + borderWidth);
}
}
五、装饰器模式的变体
1. 透明装饰器模式
// 透明装饰器接口
public interface TransparentDecorator extends VisualComponent {
void addedBehavior();
}
// 具体透明装饰器
public class ScrollDecorator implements TransparentDecorator {
private VisualComponent component;
public ScrollDecorator(VisualComponent component) {
this.component = component;
}
public void draw() {
component.draw();
drawScroll();
}
public void resize() {
component.resize();
}
public void addedBehavior() {
System.out.println("滚动行为");
}
private void drawScroll() {
System.out.println("绘制滚动条");
}
}
2. 半透明装饰器模式
// 扩展接口
public interface Scrollable {
void scrollTo(int position);
}
// 半透明装饰器
public class ScrollDecorator implements VisualComponent, Scrollable {
private VisualComponent component;
public ScrollDecorator(VisualComponent component) {
this.component = component;
}
public void draw() {
component.draw();
drawScroll();
}
public void resize() {
component.resize();
}
public void scrollTo(int position) {
System.out.println("滚动到位置: " + position);
}
private void drawScroll() {
System.out.println("绘制滚动条");
}
}
六、装饰器模式的优缺点
优点
- 灵活扩展:比继承更灵活的功能扩展方式
- 避免子类膨胀:通过组合实现功能叠加
- 动态添加功能:运行时添加或移除装饰
- 单一职责原则:每个装饰类只关注一个功能
缺点
- 复杂度增加:多层装饰可能使代码难以理解
- 小对象多:会产生许多小装饰器对象
- 初始化复杂:创建高度装饰的对象需要多步操作
七、最佳实践
- 合理设计组件接口:保持装饰器和组件接口一致
- 控制装饰层数:避免过度装饰导致复杂度过高
- 文档化装饰顺序:某些装饰器可能有顺序依赖
- 考虑性能影响:多层装饰可能带来性能开销
- 与工厂模式结合:简化装饰对象的创建过程
八、总结
装饰器模式是动态扩展对象功能的强大工具,特别适用于:
- 需要动态/透明地添加或撤销功能
- 不适合使用子类扩展的情况
- 需要组合多个独立扩展功能
- 系统需要运行时添加功能
在实际开发中,装饰器模式常见于:
- Java I/O流体系
- Web中间件开发
- GUI组件装饰
- 权限控制/日志记录等横切关注点
正确使用装饰器模式可以提高系统的灵活性和可扩展性,但需要注意不要过度使用,以免增加系统复杂性。