深入理解设计模式之装饰者模式(Decorator Pattern)
一、引言
在软件开发中,我们经常需要给对象添加新的功能。最直接的方式是通过继承来扩展类,但这种方式会导致类的数量急剧增加,且不够灵活。装饰者模式提供了一种更加灵活的替代方案:在运行时动态地给对象添加职责,而不是通过继承。
本文将深入探讨装饰者模式的原理、实现方式,并结合Java I/O流、Spring框架等实际应用,帮助你全面掌握这一重要的设计模式。
二、什么是装饰者模式
2.1 定义
装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
2.2 核心思想
- 动态扩展:在运行时给对象添加功能,而不是编译时
- 透明性:装饰者和被装饰者实现相同的接口
- 灵活组合:可以使用多个装饰者包装一个对象
- 替代继承:使用组合而非继承来扩展功能
2.3 模式结构
scss
┌──────────────────────┐
│ <<interface>> │
│ Component │ 抽象组件
├──────────────────────┤
│ + operation() │
└──────────────────────┘
△
│ 实现
┌─────┴──────┐
│ │
┌────┴────────┐ ┌┴────────────────────┐
│ Concrete │ │ Decorator │ 抽象装饰者
│ Component │ ├─────────────────────┤
├─────────────┤ │ - component │◆─→Component
│ operation() │ │ + operation() │
└─────────────┘ └─────────△───────────┘
│ 继承
┌──────┴──────┐
│ │
┌────────┴────┐ ┌────┴──────────┐
│ConcreteA │ │ConcreteB │ 具体装饰者
│Decorator │ │Decorator │
├─────────────┤ ├───────────────┤
│operation() │ │operation() │
│addedBehavior│ │addedBehavior │
└─────────────┘ └───────────────┘
调用关系:
Client → ConcreteDecoratorA → ConcreteDecoratorB → ConcreteComponent
(添加功能A) (添加功能B) (核心功能)
2.4 与继承的区别
arduino
使用继承:
Component
│
┌─────────────┼─────────────┐
│ │ │
ComponentA ComponentB ComponentC
│ │ │
┌────┴────┐ ┌───┴───┐ ┌───┴───┐
│ │ │ │ │ │
AA AB BA BB CA CB ← 类数量爆炸!
使用装饰者:
Component
│
┌───┴───┐
│ │
Concrete Decorator
│
┌───┴───┐
DecoratorA DecoratorB
组合方式:
new DecoratorA(new DecoratorB(new ConcreteComponent()))
灵活组合,避免类爆炸!
三、基础示例
3.1 场景:咖啡店饮料订单
咖啡店提供多种咖啡,顾客可以添加各种配料(牛奶、摩卡、糖浆等),每种配料都会增加价格。
抽象组件:
java
/**
* 抽象组件:饮料
*/
public interface Beverage {
/**
* 获取描述
*/
String getDescription();
/**
* 获取价格
*/
double cost();
}
具体组件:
java
/**
* 具体组件:浓缩咖啡
*/
public class Espresso implements Beverage {
@Override
public String getDescription() {
return "浓缩咖啡";
}
@Override
public double cost() {
return 15.0;
}
}
/**
* 具体组件:美式咖啡
*/
public class Americano implements Beverage {
@Override
public String getDescription() {
return "美式咖啡";
}
@Override
public double cost() {
return 18.0;
}
}
/**
* 具体组件:拿铁
*/
public class Latte implements Beverage {
@Override
public String getDescription() {
return "拿铁";
}
@Override
public double cost() {
return 22.0;
}
}
抽象装饰者:
java
/**
* 抽象装饰者:调料装饰者
*/
public abstract class CondimentDecorator implements Beverage {
/**
* 被装饰的饮料对象
*/
protected Beverage beverage;
public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}
/**
* 子类必须实现getDescription方法
*/
@Override
public abstract String getDescription();
}
具体装饰者:
java
/**
* 具体装饰者:牛奶
*/
public class Milk extends CondimentDecorator {
public Milk(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + " + 牛奶";
}
@Override
public double cost() {
return beverage.cost() + 3.0;
}
}
/**
* 具体装饰者:摩卡
*/
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + " + 摩卡";
}
@Override
public double cost() {
return beverage.cost() + 5.0;
}
}
/**
* 具体装饰者:豆浆
*/
public class Soy extends CondimentDecorator {
public Soy(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + " + 豆浆";
}
@Override
public double cost() {
return beverage.cost() + 4.0;
}
}
/**
* 具体装饰者:奶泡
*/
public class Whip extends CondimentDecorator {
public Whip(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + " + 奶泡";
}
@Override
public double cost() {
return beverage.cost() + 2.0;
}
}
客户端使用:
java
public class CoffeeShop {
public static void main(String[] args) {
// 订单1: 纯浓缩咖啡
Beverage beverage1 = new Espresso();
System.out.println(beverage1.getDescription() + " ¥" + beverage1.cost());
// 订单2: 美式咖啡 + 牛奶
Beverage beverage2 = new Americano();
beverage2 = new Milk(beverage2);
System.out.println(beverage2.getDescription() + " ¥" + beverage2.cost());
// 订单3: 拿铁 + 摩卡 + 奶泡(双重装饰)
Beverage beverage3 = new Latte();
beverage3 = new Mocha(beverage3);
beverage3 = new Whip(beverage3);
System.out.println(beverage3.getDescription() + " ¥" + beverage3.cost());
// 订单4: 浓缩咖啡 + 双份摩卡 + 牛奶 + 奶泡(多重装饰)
Beverage beverage4 = new Espresso();
beverage4 = new Mocha(beverage4);
beverage4 = new Mocha(beverage4); // 双份摩卡
beverage4 = new Milk(beverage4);
beverage4 = new Whip(beverage4);
System.out.println(beverage4.getDescription() + " ¥" + beverage4.cost());
}
}
输出:
浓缩咖啡 ¥15.0
美式咖啡 + 牛奶 ¥21.0
拿铁 + 摩卡 + 奶泡 ¥29.0
浓缩咖啡 + 摩卡 + 摩卡 + 牛奶 + 奶泡 ¥30.0
四、实际生产场景应用
4.1 场景:数据源装饰器
在企业应用中,我们需要对数据源添加各种功能:日志记录、性能监控、连接池管理等。
java
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.io.PrintWriter;
import java.util.logging.Logger;
/**
* 抽象组件:DataSource(JDK提供)
* 我们使用javax.sql.DataSource接口
*/
/**
* 具体组件:基础数据源
*/
public class BasicDataSource implements DataSource {
private String url;
private String username;
private String password;
public BasicDataSource(String url, String username, String password) {
this.url = url;
this.username = username;
this.password = password;
}
@Override
public Connection getConnection() throws SQLException {
System.out.println("创建数据库连接: " + url);
// 实际实现中会使用DriverManager.getConnection()
return null; // 简化示例
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return getConnection();
}
// 其他DataSource接口方法省略...
@Override
public PrintWriter getLogWriter() throws SQLException { return null; }
@Override
public void setLogWriter(PrintWriter out) throws SQLException {}
@Override
public void setLoginTimeout(int seconds) throws SQLException {}
@Override
public int getLoginTimeout() throws SQLException { return 0; }
@Override
public Logger getParentLogger() { return null; }
@Override
public <T> T unwrap(Class<T> iface) throws SQLException { return null; }
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; }
}
/**
* 抽象装饰者:数据源装饰器
*/
public abstract class DataSourceDecorator implements DataSource {
protected DataSource dataSource;
public DataSourceDecorator(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return dataSource.getConnection(username, password);
}
// 委托其他方法
@Override
public PrintWriter getLogWriter() throws SQLException {
return dataSource.getLogWriter();
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
dataSource.setLogWriter(out);
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
dataSource.setLoginTimeout(seconds);
}
@Override
public int getLoginTimeout() throws SQLException {
return dataSource.getLoginTimeout();
}
@Override
public Logger getParentLogger() {
return dataSource.getParentLogger();
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return dataSource.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return dataSource.isWrapperFor(iface);
}
}
具体装饰者:
java
/**
* 具体装饰者:日志记录数据源
*/
public class LoggingDataSource extends DataSourceDecorator {
public LoggingDataSource(DataSource dataSource) {
super(dataSource);
}
@Override
public Connection getConnection() throws SQLException {
long startTime = System.currentTimeMillis();
System.out.println("[LOG] 开始获取数据库连接...");
Connection connection = super.getConnection();
long endTime = System.currentTimeMillis();
System.out.println("[LOG] 获取连接成功,耗时: " + (endTime - startTime) + "ms");
return connection;
}
}
/**
* 具体装饰者:性能监控数据源
*/
public class PerformanceMonitoringDataSource extends DataSourceDecorator {
private static int connectionCount = 0;
private static long totalConnectionTime = 0;
public PerformanceMonitoringDataSource(DataSource dataSource) {
super(dataSource);
}
@Override
public Connection getConnection() throws SQLException {
long startTime = System.nanoTime();
Connection connection = super.getConnection();
long endTime = System.nanoTime();
long duration = (endTime - startTime) / 1_000_000; // 转换为毫秒
connectionCount++;
totalConnectionTime += duration;
System.out.println("[PERFORMANCE] 连接次数: " + connectionCount +
", 平均耗时: " + (totalConnectionTime / connectionCount) + "ms");
return connection;
}
public static void printStatistics() {
System.out.println("\n=== 性能统计 ===");
System.out.println("总连接次数: " + connectionCount);
System.out.println("总耗时: " + totalConnectionTime + "ms");
System.out.println("平均耗时: " + (connectionCount > 0 ? totalConnectionTime / connectionCount : 0) + "ms");
}
}
/**
* 具体装饰者:重试数据源
*/
public class RetryDataSource extends DataSourceDecorator {
private int maxRetries;
public RetryDataSource(DataSource dataSource, int maxRetries) {
super(dataSource);
this.maxRetries = maxRetries;
}
@Override
public Connection getConnection() throws SQLException {
SQLException lastException = null;
for (int i = 0; i <= maxRetries; i++) {
try {
if (i > 0) {
System.out.println("[RETRY] 第 " + i + " 次重试...");
}
return super.getConnection();
} catch (SQLException e) {
lastException = e;
if (i < maxRetries) {
try {
Thread.sleep(1000 * (i + 1)); // 递增等待时间
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
}
throw new SQLException("获取连接失败,已重试 " + maxRetries + " 次", lastException);
}
}
/**
* 具体装饰者:连接池数据源(简化版)
*/
public class PooledDataSource extends DataSourceDecorator {
private java.util.Queue<Connection> connectionPool = new java.util.LinkedList<>();
private int poolSize;
public PooledDataSource(DataSource dataSource, int poolSize) {
super(dataSource);
this.poolSize = poolSize;
initializePool();
}
private void initializePool() {
System.out.println("[POOL] 初始化连接池,大小: " + poolSize);
for (int i = 0; i < poolSize; i++) {
try {
connectionPool.offer(super.getConnection());
} catch (SQLException e) {
System.err.println("初始化连接池失败: " + e.getMessage());
}
}
}
@Override
public Connection getConnection() throws SQLException {
if (!connectionPool.isEmpty()) {
System.out.println("[POOL] 从连接池获取连接,剩余: " + connectionPool.size());
return connectionPool.poll();
} else {
System.out.println("[POOL] 连接池已空,创建新连接");
return super.getConnection();
}
}
public void returnConnection(Connection connection) {
if (connectionPool.size() < poolSize) {
connectionPool.offer(connection);
System.out.println("[POOL] 连接返回连接池,当前: " + connectionPool.size());
}
}
}
客户端使用:
java
public class DataSourceDecoratorDemo {
public static void main(String[] args) throws SQLException {
// 创建基础数据源
DataSource basicDataSource = new BasicDataSource(
"jdbc:mysql://localhost:3306/mydb",
"root",
"password"
);
// 场景1: 添加日志功能
System.out.println("=== 场景1: 基础数据源 + 日志 ===");
DataSource loggedDataSource = new LoggingDataSource(basicDataSource);
loggedDataSource.getConnection();
// 场景2: 添加日志 + 性能监控
System.out.println("\n=== 场景2: 基础数据源 + 日志 + 性能监控 ===");
DataSource monitoredDataSource = new PerformanceMonitoringDataSource(
new LoggingDataSource(basicDataSource)
);
monitoredDataSource.getConnection();
monitoredDataSource.getConnection();
// 场景3: 添加日志 + 性能监控 + 重试
System.out.println("\n=== 场景3: 完整装饰链 ===");
DataSource fullDataSource = new RetryDataSource(
new PerformanceMonitoringDataSource(
new LoggingDataSource(basicDataSource)
),
3 // 最多重试3次
);
fullDataSource.getConnection();
// 打印统计信息
PerformanceMonitoringDataSource.printStatistics();
}
}
4.2 场景:HTTP请求/响应装饰器
在Web应用中,我们需要对HTTP请求和响应进行各种处理:压缩、加密、缓存等。
java
/**
* 抽象组件:HTTP处理器
*/
public interface HttpHandler {
/**
* 处理HTTP请求
*/
String handleRequest(String request);
}
/**
* 具体组件:基础HTTP处理器
*/
public class BasicHttpHandler implements HttpHandler {
@Override
public String handleRequest(String request) {
// 模拟处理请求
return "Response for: " + request;
}
}
/**
* 抽象装饰者:HTTP处理器装饰器
*/
public abstract class HttpHandlerDecorator implements HttpHandler {
protected HttpHandler handler;
public HttpHandlerDecorator(HttpHandler handler) {
this.handler = handler;
}
@Override
public String handleRequest(String request) {
return handler.handleRequest(request);
}
}
/**
* 具体装饰者:压缩装饰器
*/
public class CompressionDecorator extends HttpHandlerDecorator {
public CompressionDecorator(HttpHandler handler) {
super(handler);
}
@Override
public String handleRequest(String request) {
// 解压请求
String decompressedRequest = decompress(request);
System.out.println("[COMPRESSION] 请求已解压");
// 调用下一个处理器
String response = super.handleRequest(decompressedRequest);
// 压缩响应
String compressedResponse = compress(response);
System.out.println("[COMPRESSION] 响应已压缩");
return compressedResponse;
}
private String decompress(String data) {
return data; // 简化实现
}
private String compress(String data) {
return "[COMPRESSED]" + data;
}
}
/**
* 具体装饰者:加密装饰器
*/
public class EncryptionDecorator extends HttpHandlerDecorator {
public EncryptionDecorator(HttpHandler handler) {
super(handler);
}
@Override
public String handleRequest(String request) {
// 解密请求
String decryptedRequest = decrypt(request);
System.out.println("[ENCRYPTION] 请求已解密");
// 调用下一个处理器
String response = super.handleRequest(decryptedRequest);
// 加密响应
String encryptedResponse = encrypt(response);
System.out.println("[ENCRYPTION] 响应已加密");
return encryptedResponse;
}
private String decrypt(String data) {
return data.replace("[ENCRYPTED]", "");
}
private String encrypt(String data) {
return "[ENCRYPTED]" + data;
}
}
/**
* 具体装饰者:缓存装饰器
*/
public class CacheDecorator extends HttpHandlerDecorator {
private java.util.Map<String, String> cache = new java.util.HashMap<>();
public CacheDecorator(HttpHandler handler) {
super(handler);
}
@Override
public String handleRequest(String request) {
// 检查缓存
if (cache.containsKey(request)) {
System.out.println("[CACHE] 命中缓存");
return cache.get(request);
}
System.out.println("[CACHE] 未命中缓存,执行请求");
// 调用下一个处理器
String response = super.handleRequest(request);
// 存入缓存
cache.put(request, response);
System.out.println("[CACHE] 响应已缓存");
return response;
}
}
/**
* 具体装饰者:日志装饰器
*/
public class LoggingDecorator extends HttpHandlerDecorator {
public LoggingDecorator(HttpHandler handler) {
super(handler);
}
@Override
public String handleRequest(String request) {
long startTime = System.currentTimeMillis();
System.out.println("\n[LOG] ========== 请求开始 ==========");
System.out.println("[LOG] 请求内容: " + request);
System.out.println("[LOG] 时间: " + new java.util.Date());
String response = super.handleRequest(request);
long endTime = System.currentTimeMillis();
System.out.println("[LOG] 响应内容: " + response);
System.out.println("[LOG] 耗时: " + (endTime - startTime) + "ms");
System.out.println("[LOG] ========== 请求结束 ==========\n");
return response;
}
}
/**
* 客户端测试
*/
public class HttpHandlerDemo {
public static void main(String[] args) {
// 创建基础处理器
HttpHandler basicHandler = new BasicHttpHandler();
// 场景1: 基础处理器 + 日志
System.out.println("=== 场景1: 基础 + 日志 ===");
HttpHandler handler1 = new LoggingDecorator(basicHandler);
handler1.handleRequest("GET /api/users");
// 场景2: 基础 + 缓存 + 日志
System.out.println("\n=== 场景2: 基础 + 缓存 + 日志 ===");
HttpHandler handler2 = new LoggingDecorator(
new CacheDecorator(basicHandler)
);
handler2.handleRequest("GET /api/products");
handler2.handleRequest("GET /api/products"); // 第二次应该命中缓存
// 场景3: 完整装饰链
System.out.println("\n=== 场景3: 完整装饰链 ===");
HttpHandler handler3 = new LoggingDecorator(
new EncryptionDecorator(
new CompressionDecorator(
new CacheDecorator(basicHandler)
)
)
);
String response = handler3.handleRequest("GET /api/sensitive-data");
System.out.println("最终响应: " + response);
}
}
五、开源框架中的应用
5.1 Java I/O流 - 装饰者模式的经典应用
Java的I/O流是装饰者模式最经典的应用案例。
java
import java.io.*;
/**
* Java I/O流的装饰者模式结构
*
* InputStream (抽象组件)
* ↑
* ├─ FileInputStream (具体组件)
* ├─ ByteArrayInputStream (具体组件)
* └─ FilterInputStream (抽象装饰者)
* ↑
* ├─ BufferedInputStream (具体装饰者)
* ├─ DataInputStream (具体装饰者)
* └─ PushbackInputStream (具体装饰者)
*/
public class JavaIODecoratorExample {
public static void main(String[] args) throws IOException {
// 示例1: 文件输入流 + 缓冲装饰器
InputStream fileInput = new FileInputStream("data.txt");
InputStream bufferedInput = new BufferedInputStream(fileInput);
// 示例2: 文件输入流 + 缓冲 + 数据类型装饰器(多重装饰)
DataInputStream dataInput = new DataInputStream(
new BufferedInputStream(
new FileInputStream("numbers.dat")
)
);
// 读取不同类型的数据
int number = dataInput.readInt();
double decimal = dataInput.readDouble();
String text = dataInput.readUTF();
dataInput.close();
// 示例3: 输出流的装饰
OutputStream fileOutput = new FileOutputStream("output.txt");
OutputStream bufferedOutput = new BufferedOutputStream(fileOutput);
DataOutputStream dataOutput = new DataOutputStream(bufferedOutput);
dataOutput.writeInt(42);
dataOutput.writeDouble(3.14);
dataOutput.writeUTF("Hello, Decorator!");
dataOutput.close();
}
}
/**
* 自定义I/O装饰者:转换为大写
*/
class UpperCaseInputStream extends FilterInputStream {
public UpperCaseInputStream(InputStream in) {
super(in);
}
@Override
public int read() throws IOException {
int c = super.read();
return (c == -1 ? c : Character.toUpperCase(c));
}
@Override
public int read(byte[] b, int offset, int len) throws IOException {
int result = super.read(b, offset, len);
for (int i = offset; i < offset + result; i++) {
b[i] = (byte) Character.toUpperCase((char) b[i]);
}
return result;
}
}
/**
* 自定义I/O装饰者:行号装饰器
*/
class LineNumberInputStream extends FilterInputStream {
private int lineNumber = 0;
private boolean newLine = true;
public LineNumberInputStream(InputStream in) {
super(in);
}
@Override
public int read() throws IOException {
int c = super.read();
if (newLine && c != -1) {
System.out.print(++lineNumber + ": ");
newLine = false;
}
if (c == '\n') {
newLine = true;
}
return c;
}
public int getLineNumber() {
return lineNumber;
}
}
/**
* 使用自定义装饰者
*/
class CustomDecoratorDemo {
public static void main(String[] args) throws IOException {
// 测试大写转换装饰器
InputStream input1 = new UpperCaseInputStream(
new ByteArrayInputStream("Hello World".getBytes())
);
int c;
while ((c = input1.read()) != -1) {
System.out.print((char) c);
}
input1.close();
System.out.println("\n");
// 测试行号装饰器
String text = "Line 1\nLine 2\nLine 3\n";
InputStream input2 = new LineNumberInputStream(
new ByteArrayInputStream(text.getBytes())
);
while ((c = input2.read()) != -1) {
System.out.print((char) c);
}
input2.close();
}
}
5.2 Spring框架中的应用
java
/**
* Spring中的BeanWrapper装饰者模式
* BeanWrapper为Bean提供了额外的功能:属性访问、类型转换等
*/
class SpringBeanWrapperExample {
public static void demonstrateBeanWrapper() {
User user = new User();
// BeanWrapper装饰了User对象,提供了额外功能
org.springframework.beans.BeanWrapper wrapper =
org.springframework.beans.PropertyAccessorFactory.forBeanPropertyAccess(user);
// 通过BeanWrapper设置属性(支持类型转换)
wrapper.setPropertyValue("name", "John");
wrapper.setPropertyValue("age", "30"); // 字符串自动转换为int
System.out.println(user.getName()); // John
System.out.println(user.getAge()); // 30
}
}
/**
* Spring中的TransactionProxyFactoryBean
* 为Bean添加事务管理功能
*/
class SpringTransactionDecoratorExample {
/*
* 配置示例(XML):
*
* <bean id="userService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
* <property name="transactionManager" ref="transactionManager"/>
* <property name="target" ref="userServiceTarget"/>
* <property name="transactionAttributes">
* <props>
* <prop key="save*">PROPAGATION_REQUIRED</prop>
* <prop key="delete*">PROPAGATION_REQUIRED</prop>
* </props>
* </property>
* </bean>
*
* 实际得到的userService是被事务装饰后的代理对象
*/
}
/**
* Spring Cache装饰器
*/
class SpringCacheDecoratorExample {
// 使用@Cacheable注解装饰方法,添加缓存功能
// @Cacheable("users")
public User getUserById(Long id) {
System.out.println("从数据库查询用户: " + id);
// 实际数据库查询
return new User();
}
// Spring会创建一个代理对象,装饰getUserById方法
// 添加缓存检查和缓存存储的功能
}
5.3 Servlet API中的应用
java
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
/**
* HttpServletRequestWrapper和HttpServletResponseWrapper
* 是Servlet API提供的装饰者基类
*/
public class RequestResponseDecoratorExample {
/**
* 自定义请求装饰器:添加请求日志
*/
static class LoggingRequestWrapper extends HttpServletRequestWrapper {
public LoggingRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
System.out.println("[REQUEST] 参数 " + name + " = " + value);
return value;
}
}
/**
* 自定义响应装饰器:添加响应头
*/
static class CustomHeaderResponseWrapper extends HttpServletResponseWrapper {
public CustomHeaderResponseWrapper(HttpServletResponse response) {
super(response);
}
@Override
public void setStatus(int sc) {
super.setStatus(sc);
super.setHeader("X-Custom-Header", "Decorated-Response");
System.out.println("[RESPONSE] 添加自定义响应头");
}
}
/**
* 过滤器中使用装饰器
*/
static class DecoratorFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 装饰请求和响应
HttpServletRequest decoratedRequest =
new LoggingRequestWrapper((HttpServletRequest) request);
HttpServletResponse decoratedResponse =
new CustomHeaderResponseWrapper((HttpServletResponse) response);
// 传递装饰后的对象
chain.doFilter(decoratedRequest, decoratedResponse);
}
@Override
public void destroy() {
}
}
}
5.4 MyBatis中的应用
java
/**
* MyBatis的Executor装饰器
* MyBatis使用装饰者模式为Executor添加缓存功能
*/
class MyBatisExecutorDecoratorExample {
/*
* MyBatis的Executor层次结构:
*
* Executor (接口)
* ↑
* ├─ BaseExecutor (抽象基类)
* │ ↑
* │ ├─ SimpleExecutor (具体实现)
* │ ├─ ReuseExecutor (具体实现)
* │ └─ BatchExecutor (具体实现)
* │
* └─ CachingExecutor (装饰器)
* 装饰任何Executor,添加二级缓存功能
*
* 创建过程:
* Executor executor = new SimpleExecutor();
* executor = new CachingExecutor(executor); // 装饰,添加缓存
*/
public void demonstrateMyBatisDecorator() {
// 简化的MyBatis Executor装饰示例
// 1. 创建基础执行器
// Executor executor = new SimpleExecutor(configuration, transaction);
// 2. 如果启用了二级缓存,使用CachingExecutor装饰
// if (cacheEnabled) {
// executor = new CachingExecutor(executor);
// }
// 3. 应用插件(也是装饰器)
// executor = (Executor) interceptorChain.pluginAll(executor);
}
}
/**
* 简化的MyBatis Executor装饰器实现
*/
interface Executor {
<E> java.util.List<E> query(String sql, Object parameter);
}
class SimpleExecutor implements Executor {
@Override
public <E> java.util.List<E> query(String sql, Object parameter) {
System.out.println("执行SQL: " + sql);
return new java.util.ArrayList<>();
}
}
class CachingExecutor implements Executor {
private Executor delegate;
private java.util.Map<String, java.util.List<?>> cache = new java.util.HashMap<>();
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
}
@Override
public <E> java.util.List<E> query(String sql, Object parameter) {
String cacheKey = sql + ":" + parameter;
// 检查缓存
if (cache.containsKey(cacheKey)) {
System.out.println("[CACHE] 命中缓存");
return (java.util.List<E>) cache.get(cacheKey);
}
// 执行查询
java.util.List<E> result = delegate.query(sql, parameter);
// 存入缓存
cache.put(cacheKey, result);
System.out.println("[CACHE] 结果已缓存");
return result;
}
}
六、装饰者模式的优缺点
6.1 优点
1. 比继承更灵活
scala
继承:编译时静态确定
class SpecialComponent extends Component {
// 功能固定
}
装饰者:运行时动态组合
Component component = new ConcreteComponent();
component = new DecoratorA(component);
component = new DecoratorB(component);
// 功能可以灵活组合
2. 遵循开闭原则
- 添加新装饰器无需修改现有代码
- 可以随意组合装饰器
3. 遵循单一职责原则
- 每个装饰器只负责一个功能
- 可以根据需要选择装饰器
4. 可以动态添加/撤销功能
java
// 运行时添加功能
Component component = new ConcreteComponent();
if (needLogging) {
component = new LoggingDecorator(component);
}
if (needCaching) {
component = new CachingDecorator(component);
}
6.2 缺点
1. 产生很多小对象
arduino
装饰链:
new DecoratorD(
new DecoratorC(
new DecoratorB(
new DecoratorA(
new ConcreteComponent()
)
)
)
)
创建了5个对象!
2. 调试困难
- 多层装饰导致堆栈跟踪复杂
- 难以理解最终对象的行为
3. 装饰顺序可能影响结果
java
// 顺序1: 先加密后压缩
new CompressionDecorator(new EncryptionDecorator(component))
// 顺序2: 先压缩后加密
new EncryptionDecorator(new CompressionDecorator(component))
// 结果可能不同!
七、最佳实践
7.1 提供便捷的构建方法
java
/**
* 装饰器构建器
*/
public class DataSourceBuilder {
private DataSource dataSource;
public DataSourceBuilder(DataSource dataSource) {
this.dataSource = dataSource;
}
public DataSourceBuilder withLogging() {
this.dataSource = new LoggingDataSource(dataSource);
return this;
}
public DataSourceBuilder withPerformanceMonitoring() {
this.dataSource = new PerformanceMonitoringDataSource(dataSource);
return this;
}
public DataSourceBuilder withRetry(int maxRetries) {
this.dataSource = new RetryDataSource(dataSource, maxRetries);
return this;
}
public DataSourceBuilder withPool(int poolSize) {
this.dataSource = new PooledDataSource(dataSource, poolSize);
return this;
}
public DataSource build() {
return dataSource;
}
}
/**
* 使用构建器
*/
class BuilderDemo {
public static void main(String[] args) {
DataSource dataSource = new DataSourceBuilder(
new BasicDataSource("jdbc:mysql://localhost/db", "user", "pass")
)
.withLogging()
.withPerformanceMonitoring()
.withRetry(3)
.withPool(10)
.build();
// 清晰、易读的装饰器组合
}
}
7.2 使用接口而非抽象类
java
/**
* 使用接口作为抽象装饰者(更灵活)
*/
public interface MessageService {
void sendMessage(String message);
}
/**
* 装饰器实现接口并持有接口引用
*/
public class EncryptedMessageService implements MessageService {
private final MessageService messageService;
public EncryptedMessageService(MessageService messageService) {
this.messageService = messageService;
}
@Override
public void sendMessage(String message) {
String encrypted = encrypt(message);
messageService.sendMessage(encrypted);
}
private String encrypt(String message) {
return "[ENCRYPTED]" + message;
}
}
7.3 考虑使用Java 8+的函数式接口
java
import java.util.function.Function;
/**
* 使用函数式编程实现装饰器
*/
public class FunctionalDecorator {
public static void main(String[] args) {
// 基础函数
Function<String, String> base = input -> "Processed: " + input;
// 装饰器:添加日志
Function<String, String> withLogging = input -> {
System.out.println("Input: " + input);
String result = base.apply(input);
System.out.println("Output: " + result);
return result;
};
// 装饰器:转换为大写
Function<String, String> withUpperCase = input ->
base.apply(input).toUpperCase();
// 组合装饰器
Function<String, String> combined = base
.andThen(String::toUpperCase)
.andThen(s -> "[DECORATED]" + s);
System.out.println(combined.apply("hello"));
// 输出: [DECORATED]PROCESSED: HELLO
}
}
7.4 文档化装饰器的影响
java
/**
* 数据源装饰器基类
*
* 使用指南:
* 1. 装饰器可以任意组合
* 2. 建议的装饰顺序:日志 → 监控 → 重试 → 连接池
* 3. 性能影响:每个装饰器增加约0.1ms开销
*
* 示例:
* <pre>
* DataSource ds = new BasicDataSource(...);
* ds = new LoggingDataSource(ds); // +0.1ms
* ds = new PerformanceMonitoringDataSource(ds); // +0.1ms
* ds = new RetryDataSource(ds, 3); // +0-3000ms (失败时)
* ds = new PooledDataSource(ds, 10); // -10ms (池化后)
* </pre>
*
* 注意事项:
* - 避免过度装饰(建议不超过4层)
* - 装饰顺序会影响行为
* - 某些装饰器可能不兼容
*/
public abstract class DocumentedDataSourceDecorator extends DataSourceDecorator {
public DocumentedDataSourceDecorator(DataSource dataSource) {
super(dataSource);
}
}
八、总结
8.1 核心要点
- 装饰者模式的本质:动态地给对象添加职责,而不改变其结构
- 适用场景 :
- 需要动态添加功能
- 使用继承会导致类爆炸
- 需要灵活组合多种功能
- 关键原则 :
- 装饰者和被装饰者有相同的接口
- 装饰者持有被装饰者的引用
- 可以透明地替换被装饰者
8.2 使用建议
arduino
选择装饰者模式的检查清单:
✓ 是否需要在运行时动态添加功能?
✓ 是否有多种功能可以任意组合?
✓ 使用继承是否会导致类数量爆炸?
✓ 是否需要对某些对象添加功能,而其他对象不需要?
如果以上都是"是",那么装饰者模式是个好选择!
8.3 与其他模式的对比
diff
装饰者 vs 代理模式:
- 装饰者:增强功能
- 代理:控制访问
装饰者 vs 适配器模式:
- 装饰者:保持接口不变,增加功能
- 适配器:改变接口,使其兼容
装饰者 vs 组合模式:
- 装饰者:只有一个子组件
- 组合:可以有多个子组件
8.4 实践经验
- 保持简单:不要过度装饰(建议不超过3-4层)
- 注意顺序:某些装饰器的顺序会影响结果
- 提供便捷方法:使用Builder或工厂简化装饰器创建
- 文档化:清楚说明各装饰器的作用和影响