1. 装饰模式深度解析:从咖啡店到Java I/O
装饰模式(Decorator Pattern)是我在多年Java开发中最常使用的设计模式之一。它完美解决了在不修改原有代码的情况下扩展对象功能的难题。记得第一次在项目中应用装饰模式是为一个电商系统实现促销功能,基础价格需要叠加各种优惠活动,装饰模式让这个需求变得异常简单。
1.1 模式本质与核心价值
装饰模式的核心在于动态组合而非静态继承。与继承的"是一个"关系不同,装饰模式体现的是"有一个"的关系。这种设计带来了几个关键优势:
- 运行时扩展:可以在程序运行时动态地添加或移除功能,而不需要在编译时确定
- 避免类爆炸:通过少量类的组合替代大量子类的继承,极大减少了类的数量
- 单一职责:每个装饰类只关注自己添加的功能,符合单一职责原则
我在实际项目中最欣赏的是装饰模式对开闭原则的完美实践。当需要新增功能时,只需要添加新的装饰类,完全不需要修改现有代码,这大大降低了引入bug的风险。
1.2 模式结构深度拆解
让我们再深入看看装饰模式的四个核心角色:
java复制// 抽象组件
public interface Component {
void operation();
}
// 具体组件
public class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("具体组件的操作");
}
}
// 抽象装饰类
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation();
}
}
// 具体装饰类
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
addedBehavior();
}
private void addedBehavior() {
System.out.println("装饰器A添加的行为");
}
}
这个结构的关键点在于:
- 装饰器和具体组件实现相同的接口
- 装饰器持有组件对象的引用
- 装饰器可以在调用组件方法前后添加自己的行为
1.3 咖啡店案例的工程实践
咖啡店的例子虽然经典,但在实际开发中我们可以做得更专业。以下是几个工程实践要点:
配置化装饰:在实际项目中,装饰的顺序和组合可能来自配置。我们可以实现一个装饰器工厂:
java复制public class CoffeeDecoratorFactory {
public static Beverage decorate(Beverage beverage, List<String> condiments) {
for (String condiment : condiments) {
switch (condiment) {
case "milk":
beverage = new Milk(beverage);
break;
case "mocha":
beverage = new Mocha(beverage);
break;
// 其他调料...
}
}
return beverage;
}
}
装饰器缓存:对于频繁使用的装饰组合,可以考虑使用享元模式缓存装饰后的对象。
装饰器与Builder模式结合:当装饰层级较深时,可以使用Builder模式使客户端代码更清晰:
java复制public class CoffeeBuilder {
private Beverage beverage;
public CoffeeBuilder(Beverage baseBeverage) {
this.beverage = baseBeverage;
}
public CoffeeBuilder addMilk() {
beverage = new Milk(beverage);
return this;
}
public CoffeeBuilder addMocha() {
beverage = new Mocha(beverage);
return this;
}
public Beverage build() {
return beverage;
}
}
// 使用示例
Beverage coffee = new CoffeeBuilder(new Espresso())
.addMilk()
.addMocha()
.build();
2. Java I/O中的装饰模式实战解析
Java I/O流是装饰模式最经典的实现,也是理解装饰模式实际价值的最佳案例。我在处理文件上传功能时,深刻体会到了这种设计的精妙之处。
2.1 Java I/O的装饰层次
Java I/O的装饰结构非常清晰:
code复制InputStream (抽象组件)
├─ FileInputStream (具体组件)
├─ FilterInputStream (抽象装饰类)
├─ BufferedInputStream (具体装饰类)
├─ DataInputStream (具体装饰类)
├─ PushbackInputStream (具体装饰类)
同样的结构也存在于输出流体系中。这种设计允许我们自由组合各种功能:
java复制// 基础文件读取
InputStream fileStream = new FileInputStream("data.txt");
// 添加缓冲功能
InputStream bufferedStream = new BufferedInputStream(fileStream);
// 添加数据反序列化功能
DataInputStream dataStream = new DataInputStream(bufferedStream);
// 添加解压功能(假设我们有一个GZIP装饰器)
InputStream gzipStream = new GZIPInputStream(dataStream);
2.2 自定义装饰器实践
在实际项目中,我们经常需要自定义装饰器。比如实现一个加密解密流:
java复制public class CryptoInputStream extends FilterInputStream {
private final Cipher cipher;
public CryptoInputStream(InputStream in, SecretKey key) throws GeneralSecurityException {
super(in);
this.cipher = Cipher.getInstance("AES");
this.cipher.init(Cipher.DECRYPT_MODE, key);
}
@Override
public int read() throws IOException {
// 实现解密逻辑
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int bytesRead = super.read(b, off, len);
if (bytesRead > 0) {
byte[] decrypted = cipher.update(b, off, bytesRead);
System.arraycopy(decrypted, 0, b, off, decrypted.length);
return decrypted.length;
}
return bytesRead;
}
}
这样我们就可以轻松地为任何输入流添加加密功能:
java复制InputStream secureStream = new CryptoInputStream(
new BufferedInputStream(
new FileInputStream("secure.data")),
secretKey);
2.3 I/O装饰模式的最佳实践
- 资源管理:装饰后的流关闭时,只需要关闭最外层的流,内层流会自动关闭
- 性能考量:装饰顺序会影响性能,通常缓冲装饰器应该放在靠近数据源的位置
- 异常处理:多层装饰时,异常可能会被包装,需要注意异常类型和处理方式
- 调试技巧:可以插入一个调试装饰器来记录流经的数据:
java复制public class DebugInputStream extends FilterInputStream {
public DebugInputStream(InputStream in) {
super(in);
}
@Override
public int read() throws IOException {
int data = super.read();
System.out.println("Read byte: " + data);
return data;
}
}
3. 装饰模式在Spring框架中的高级应用
Spring框架中大量使用了装饰模式的思想,虽然不是严格意义上的装饰模式实现,但设计理念高度一致。我在开发Spring Boot应用时,经常需要与这些装饰器打交道。
3.1 Spring Security的过滤器链
Spring Security的过滤器链是装饰模式的典型应用:
java复制public class SecurityFilterChain {
private List<Filter> filters;
public void doFilter(ServletRequest request, ServletResponse response) {
// 装饰器模式的变体实现
for (Filter filter : filters) {
filter.doFilter(request, response);
}
}
}
每个安全过滤器都可以看作是一个装饰器,为请求处理添加特定的安全功能,如认证、授权、CSRF保护等。
3.2 Spring Web的HandlerInterceptor
Spring MVC的拦截器机制也体现了装饰模式的思想:
java复制public class CompositeHandlerInterceptor implements HandlerInterceptor {
private List<HandlerInterceptor> interceptors;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
for (HandlerInterceptor interceptor : interceptors) {
if (!interceptor.preHandle(request, response, handler)) {
return false;
}
}
return true;
}
}
这种设计允许我们灵活地添加各种横切关注点,如日志记录、性能监控、权限检查等。
3.3 Spring缓存抽象中的装饰模式
Spring的缓存抽象使用了装饰模式来支持多种缓存实现:
java复制public class TransactionAwareCacheDecorator implements Cache {
private final Cache targetCache;
public TransactionAwareCacheDecorator(Cache targetCache) {
this.targetCache = targetCache;
}
@Override
public ValueWrapper get(Object key) {
// 添加事务感知逻辑
return targetCache.get(key);
}
}
这种设计使得缓存实现可以透明地添加事务支持、统计功能等,而不需要修改底层缓存实现。
4. 装饰模式在复杂业务系统中的实战技巧
在大型业务系统中,装饰模式的应用需要更多的工程考量。我在金融系统开发中积累了一些实用经验。
4.1 电商促销系统的装饰实现
电商促销是装饰模式的绝佳应用场景。我们来看一个复杂的实现:
java复制// 基础价格接口
public interface Price {
BigDecimal getPrice();
String getDescription();
}
// 商品基础价格
public class BasePrice implements Price {
private BigDecimal amount;
public BasePrice(BigDecimal amount) {
this.amount = amount;
}
@Override
public BigDecimal getPrice() {
return amount;
}
@Override
public String getDescription() {
return "商品价格";
}
}
// 促销装饰器抽象类
public abstract class PromotionDecorator implements Price {
protected Price decoratedPrice;
public PromotionDecorator(Price decoratedPrice) {
this.decoratedPrice = decoratedPrice;
}
}
// 满减促销
public class FullReductionPromotion extends PromotionDecorator {
private BigDecimal fullAmount;
private BigDecimal reduction;
public FullReductionPromotion(Price decoratedPrice, BigDecimal fullAmount, BigDecimal reduction) {
super(decoratedPrice);
this.fullAmount = fullAmount;
this.reduction = reduction;
}
@Override
public BigDecimal getPrice() {
BigDecimal basePrice = decoratedPrice.getPrice();
if (basePrice.compareTo(fullAmount) >= 0) {
return basePrice.subtract(reduction);
}
return basePrice;
}
@Override
public String getDescription() {
return decoratedPrice.getDescription() + ", 满" + fullAmount + "减" + reduction;
}
}
// 折扣促销
public class DiscountPromotion extends PromotionDecorator {
private BigDecimal discountRate; // 0.8表示8折
public DiscountPromotion(Price decoratedPrice, BigDecimal discountRate) {
super(decoratedPrice);
this.discountRate = discountRate;
}
@Override
public BigDecimal getPrice() {
return decoratedPrice.getPrice().multiply(discountRate);
}
@Override
public String getDescription() {
return decoratedPrice.getDescription() + ", " + discountRate.multiply(BigDecimal.TEN) + "折优惠";
}
}
使用示例:
java复制Price price = new BasePrice(new BigDecimal("1000"));
price = new FullReductionPromotion(price, new BigDecimal("500"), new BigDecimal("100"));
price = new DiscountPromotion(price, new BigDecimal("0.8"));
System.out.println(price.getDescription());
// 输出: 商品价格, 满500减100, 8折优惠
System.out.println(price.getPrice());
// 输出: 720 (1000-100=900, 900*0.8=720)
4.2 权限系统的装饰实现
另一个典型场景是权限系统。我们可以用装饰模式动态添加权限检查:
java复制public interface UserService {
void updateProfile(User user);
void changePassword(User user);
}
public class BasicUserService implements UserService {
@Override
public void updateProfile(User user) {
// 基础实现
}
@Override
public void changePassword(User user) {
// 基础实现
}
}
public class PermissionCheckDecorator implements UserService {
private UserService decoratedService;
private PermissionChecker checker;
public PermissionCheckDecorator(UserService decoratedService, PermissionChecker checker) {
this.decoratedService = decoratedService;
this.checker = checker;
}
@Override
public void updateProfile(User user) {
if (checker.hasPermission(user, "profile.update")) {
decoratedService.updateProfile(user);
} else {
throw new PermissionDeniedException();
}
}
@Override
public void changePassword(User user) {
if (checker.hasPermission(user, "password.change")) {
decoratedService.changePassword(user);
} else {
throw new PermissionDeniedException();
}
}
}
4.3 日志系统的装饰实现
日志系统也是装饰模式的常见应用场景:
java复制public interface DataService {
String fetchData(String key);
}
public class BasicDataService implements DataService {
@Override
public String fetchData(String key) {
// 从数据库获取数据
return "data for " + key;
}
}
public class LoggingDecorator implements DataService {
private DataService decoratedService;
private Logger logger;
public LoggingDecorator(DataService decoratedService, Logger logger) {
this.decoratedService = decoratedService;
this.logger = logger;
}
@Override
public String fetchData(String key) {
logger.info("开始获取数据,key: " + key);
long start = System.currentTimeMillis();
try {
String result = decoratedService.fetchData(key);
long duration = System.currentTimeMillis() - start;
logger.info("成功获取数据,key: " + key + ", 耗时: " + duration + "ms");
return result;
} catch (Exception e) {
logger.error("获取数据失败,key: " + key, e);
throw e;
}
}
}
5. 装饰模式的高级话题与性能优化
当系统规模扩大时,装饰模式的应用需要考虑更多高级话题。我在处理高并发系统时积累了一些优化经验。
5.1 装饰模式的性能考量
多层装饰会带来一定的性能开销,主要体现在:
- 方法调用开销:每个装饰层都会增加一次方法调用
- 对象创建开销:每个装饰器都是一个独立对象
- 内存占用:装饰器链会占用更多内存
优化建议:
- 减少装饰层数:评估是否所有装饰都是必要的
- 缓存装饰对象:对于频繁使用的装饰组合,考虑缓存装饰后的对象
- 使用轻量级装饰器:避免在装饰器中存储大量状态
5.2 装饰模式与AOP的对比
装饰模式和AOP(面向切面编程)都能实现横切关注点,但它们有本质区别:
| 特性 | 装饰模式 | AOP |
|---|---|---|
| 实现方式 | 静态代码,编译时确定 | 动态代理,运行时织入 |
| 灵活性 | 相对固定,需要显式组合 | 更灵活,可以通过配置定义切面 |
| 可见性 | 代码中显式可见 | 对业务代码透明 |
| 适用场景 | 需要精细控制的扩展点 | 横跨多个类的通用关注点 |
在实际项目中,我通常这样选择:
- 当扩展点明确且需要精细控制时,使用装饰模式
- 当关注点横跨多个类且不需要修改业务代码时,使用AOP
5.3 装饰模式的线程安全问题
装饰器本身通常是无状态的,线程安全问题主要来自:
- 被装饰对象的状态:如果被装饰对象不是线程安全的,装饰后仍然不安全
- 装饰器的共享:同一个装饰器实例被多个线程共享时可能有问题
最佳实践:
- 明确线程安全边界:文档中明确说明装饰器是否线程安全
- 使用线程局部变量:对于需要保持状态的装饰器,考虑使用ThreadLocal
- 避免共享可变状态:装饰器尽量设计为无状态的
5.4 装饰模式的测试策略
测试装饰器时需要特别关注:
- 单元测试装饰器本身:验证装饰器添加的行为是否正确
- 集成测试装饰链:验证多个装饰器组合后的行为
- 边界条件测试:特别是装饰器可能改变被装饰对象行为的情况
测试示例:
java复制@Test
public void testLoggingDecorator() {
DataService mockService = mock(DataService.class);
when(mockService.fetchData("test")).thenReturn("test data");
Logger logger = mock(Logger.class);
DataService decorated = new LoggingDecorator(mockService, logger);
String result = decorated.fetchData("test");
assertEquals("test data", result);
verify(logger).info("开始获取数据,key: test");
verify(logger).info(contains("成功获取数据"));
verify(mockService).fetchData("test");
}
6. 装饰模式的替代方案与反模式
虽然装饰模式非常强大,但并非所有场景都适用。我在架构评审中经常需要判断何时使用装饰模式,何时选择其他方案。
6.1 何时不使用装饰模式
以下情况可能不适合使用装饰模式:
- 对象接口不稳定:如果组件接口经常变化,装饰模式会难以维护
- 需要彻底改变行为:装饰模式适合增强功能,而非完全改变行为
- 性能极其敏感的场景:多层装饰带来的开销可能不可接受
- 简单的一次性扩展:如果扩展很简单且不会变化,直接修改可能更合适
6.2 装饰模式的常见反模式
- 装饰器链过长:超过3-4层的装饰链会难以理解和维护
- 装饰器相互依赖:装饰器之间不应该有依赖关系
- 装饰器修改组件状态:装饰器应该只添加行为,不修改组件内部状态
- 忽略开闭原则:为了添加新功能而修改现有装饰器
6.3 替代方案比较
-
策略模式:
- 适合:完全替换算法或行为
- 不适合:需要累积功能的情况
-
组合模式:
- 适合:部分-整体层次结构
- 不适合:动态添加职责
-
代理模式:
- 适合:控制访问,延迟初始化
- 不适合:功能叠加
实际案例选择:
- 在实现缓存系统时,我开始使用了装饰模式,但当缓存策略变得复杂时,切换到策略模式与装饰模式结合的方式更合适
7. 现代Java中的装饰模式演进
随着Java语言的发展,装饰模式也有新的实现方式。我在Java 8+项目中尝试了一些新方法。
7.1 使用Lambda表达式简化装饰器
对于简单的装饰逻辑,可以使用Lambda表达式:
java复制public class FunctionalDecorator {
public static void main(String[] args) {
Function<String, String> basicFunction = s -> "Hello " + s;
// 添加装饰逻辑
Function<String, String> decoratedFunction = basicFunction
.andThen(s -> s + "!")
.andThen(s -> s.toUpperCase());
System.out.println(decoratedFunction.apply("world"));
// 输出: HELLO WORLD!
}
}
7.2 使用默认方法的接口装饰
Java 8的接口默认方法也可以用于实现轻量级装饰:
java复制public interface Reader {
String read();
default Reader withTrim() {
return () -> read().trim();
}
default Reader withUpperCase() {
return () -> read().toUpperCase();
}
}
public class BasicReader implements Reader {
@Override
public String read() {
return " some text ";
}
}
// 使用示例
Reader reader = new BasicReader()
.withTrim()
.withUpperCase();
System.out.println(reader.read()); // 输出: "SOME TEXT"
7.3 模块化系统中的装饰模式
在Java 9+的模块系统中,装饰模式需要注意:
- 模块导出:确保装饰器和被装饰类型在同一个模块或导出到需要的模块
- 服务加载:可以使用ServiceLoader机制动态加载装饰器
- 模块间装饰:跨模块装饰需要仔细设计接口
示例模块配置:
java复制module mymodule {
exports com.example.decorator;
provides com.example.decorator.DecoratorService
with com.example.decorator.MyDecorator;
}
8. 装饰模式与其他模式的协同应用
在实际项目中,装饰模式很少单独使用。我在架构设计中经常将它与其他模式结合。
8.1 装饰模式与工厂模式结合
使用工厂模式管理装饰器的创建:
java复制public class DecoratorFactory {
public static Price applyPromotions(Price basePrice, List<Promotion> promotions) {
Price result = basePrice;
for (Promotion promotion : promotions) {
switch (promotion.getType()) {
case DISCOUNT:
result = new DiscountPromotion(result, promotion.getAmount());
break;
case FULL_REDUCTION:
result = new FullReductionPromotion(result,
promotion.getCondition(), promotion.getAmount());
break;
// 其他促销类型...
}
}
return result;
}
}
8.2 装饰模式与组合模式结合
处理树形结构时,可以结合两种模式:
java复制public interface Component {
void operation();
}
public class Leaf implements Component {
@Override
public void operation() {
// 叶子节点操作
}
}
public class DecoratedLeaf extends Leaf {
private Component decorated;
public DecoratedLeaf(Component decorated) {
this.decorated = decorated;
}
@Override
public void operation() {
// 前置处理
decorated.operation();
// 后置处理
}
}
public class Composite implements Component {
private List<Component> children = new ArrayList<>();
public void add(Component component) {
children.add(component);
}
@Override
public void operation() {
for (Component child : children) {
child.operation();
}
}
}
8.3 装饰模式与责任链模式的区别
这两种模式经常被混淆,但它们有本质区别:
| 特性 | 装饰模式 | 责任链模式 |
|---|---|---|
| 目的 | 增强对象功能 | 处理请求或命令 |
| 控制流 | 总是委托给被装饰对象 | 可能中断传递 |
| 组合方式 | 静态组合,编译时确定 | 动态组合,运行时确定 |
| 结果处理 | 通常修改或增强返回值 | 可能完全不处理请求 |
实际项目中,我曾经将两者结合使用,装饰模式处理功能增强,责任链模式处理业务流程。
9. 装饰模式在微服务架构中的应用
在微服务架构下,装饰模式有了新的应用场景。我在设计微服务网关时大量应用了装饰理念。
9.1 微服务客户端的装饰实现
为微服务客户端添加重试、熔断等功能:
java复制public interface ServiceClient {
String callService(String param);
}
public class RetryDecorator implements ServiceClient {
private ServiceClient decorated;
private int maxRetries;
public RetryDecorator(ServiceClient decorated, int maxRetries) {
this.decorated = decorated;
this.maxRetries = maxRetries;
}
@Override
public String callService(String param) {
int retries = 0;
while (true) {
try {
return decorated.callService(param);
} catch (Exception e) {
if (++retries >= maxRetries) {
throw e;
}
// 等待后重试
try { Thread.sleep(100 * retries); }
catch (InterruptedException ie) { Thread.currentThread().interrupt(); }
}
}
}
}
9.2 API网关中的装饰模式
API网关可以使用装饰模式逐步构建处理管道:
java复制public interface ApiHandler {
Response handle(Request request);
}
public class LoggingHandler implements ApiHandler {
private ApiHandler decorated;
public LoggingHandler(ApiHandler decorated) {
this.decorated = decorated;
}
@Override
public Response handle(Request request) {
logRequest(request);
try {
Response response = decorated.handle(request);
logResponse(response);
return response;
} catch (Exception e) {
logError(e);
throw e;
}
}
}
public class AuthHandler implements ApiHandler {
private ApiHandler decorated;
public AuthHandler(ApiHandler decorated) {
this.decorated = decorated;
}
@Override
public Response handle(Request request) {
if (!checkAuth(request)) {
throw new UnauthorizedException();
}
return decorated.handle(request);
}
}
9.3 服务网格中的装饰思想
服务网格(Sidecar)模式本质上是装饰模式的分布式实现:
- 基础服务:业务微服务
- 装饰器:Sidecar代理,处理观测、安全、流量控制等
- 动态组合:通过配置决定哪些功能被启用
这种架构让业务服务可以专注于核心逻辑,而基础设施功能由Sidecar"装饰"。
10. Kotlin中的装饰模式实现
作为JVM上的现代语言,Kotlin提供了更简洁的装饰模式实现方式。我在Kotlin项目中尝试了这些新特性。
10.1 使用类委托简化装饰器
Kotlin的类委托特性可以极大简化装饰器的实现:
kotlin复制interface Coffee {
fun cost(): Double
fun description(): String
}
class SimpleCoffee : Coffee {
override fun cost() = 1.0
override fun description() = "Simple coffee"
}
class MilkDecorator(private val coffee: Coffee) : Coffee by coffee {
override fun cost() = coffee.cost() + 0.5
override fun description() = coffee.description() + ", milk"
}
by关键字自动委托所有方法,我们只需要重写需要装饰的方法。
10.2 使用扩展函数实现轻量级装饰
对于简单的功能增强,Kotlin扩展函数是很好的选择:
kotlin复制fun Coffee.withMilk(): Coffee = object : Coffee by this {
override fun cost() = this@withMilk.cost() + 0.5
override fun description() = this@withMilk.description() + ", milk"
}
// 使用示例
val coffee = SimpleCoffee()
.withMilk()
.withSugar()
10.3 Kotlin属性委托实现装饰
Kotlin的属性委托也可以用于实现装饰模式:
kotlin复制class LoggingProperty<T>(private val delegate: ReadWriteProperty<Any?, T>)
: ReadWriteProperty<Any?, T> by delegate {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
val value = delegate.getValue(thisRef, property)
println("${property.name} = $value")
return value
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
println("Setting ${property.name} to $value")
delegate.setValue(thisRef, property, value)
}
}
// 使用示例
class Example {
var decoratedProperty: String by LoggingProperty(::delegatedProperty)
private var delegatedProperty by Delegates.notNull<String>()
}
11. 装饰模式在Android开发中的实践
在Android开发中,装饰模式也有很多应用场景。我在开发Android应用时积累了一些实用技巧。
11.1 Android视图系统的装饰应用
Android的View系统本身使用了装饰模式的思想:
java复制// 基础视图
TextView textView = new TextView(context);
// 装饰后的视图
CardView cardView = new CardView(context);
cardView.addView(textView);
我们可以自定义视图装饰器:
java复制public class HighlightDecorator extends ViewGroup {
private View decoratedView;
public HighlightDecorator(Context context, View decoratedView) {
super(context);
this.decoratedView = decoratedView;
addView(decoratedView);
setBackgroundResource(R.drawable.highlight_border);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
decoratedView.layout(0, 0, r - l, b - t);
}
}
// 使用示例
View decorated = new HighlightDecorator(context, originalView);
11.2 OkHttp拦截器中的装饰模式
OkHttp的拦截器机制是装饰模式的优秀实现:
java复制OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.addInterceptor(new AuthInterceptor())
.addNetworkInterceptor(new CacheInterceptor())
.build();
每个拦截器都可以看作是一个装饰器,为请求处理添加特定功能。
11.3 Room数据库的装饰应用
在Room数据库中使用装饰模式添加功能:
java复制public class TransactionDecorator implements MyDao {
private final MyDao decorated;
private final RoomDatabase database;
public TransactionDecorator(MyDao decorated, RoomDatabase database) {
this.decorated = decorated;
this.database = database;
}
@Override
public void insertData(Data data) {
database.runInTransaction(() -> {
decorated.insertData(data);
// 其他操作...
});
}
}
12. 装饰模式在前端框架中的应用
现代前端框架也广泛使用装饰模式的思想。我在React项目中实践了这些模式。
12.1 React高阶组件(HOC)中的装饰模式
高阶组件本质上是React版的装饰器:
javascript复制function withLogging(WrappedComponent) {
return class extends React.Component {
componentDidMount() {
console.log(`Component ${WrappedComponent.name} mounted`);
}
render() {
return <WrappedComponent {...this.props} />;
}
};
}
// 使用示例
const EnhancedComponent = withLogging(MyComponent);
12.2 React Hook中的装饰思想
Hook可以看作是一种更轻量的装饰方式:
javascript复制function useLogger(componentName) {
useEffect(() => {
console.log(`${componentName} mounted`);
return () => console.log(`${componentName} unmounted`);
}, [componentName]);
}
function MyComponent() {
useLogger("MyComponent");
// 组件逻辑...
}
12.3 Redux中间件中的装饰模式
Redux中间件机制也是装饰模式的实现:
javascript复制const loggerMiddleware = store => next => action => {
console.log('dispatching', action);
let result = next(action);
console.log('next state', store.getState());
return result;
};
const store = createStore(
reducer,
applyMiddleware(loggerMiddleware, thunkMiddleware)
);
每个中间件都可以看作是一个装饰器,增强dispatch的功能。
13. 装饰模式在测试中的妙用
在测试代码中,装饰模式可以帮助我们构建更灵活的测试工具。我在编写测试框架时深有体会。
13.1 测试用例的装饰实现
为测试用例添加前置后置操作:
java复制public interface TestCase {
void runTest();
}
public class LoggingTestCase implements TestCase {
private TestCase decorated;
public LoggingTestCase(TestCase decorated) {
this.decorated = decorated;
}
@Override
public void runTest() {
System.out.println("Starting test...");
long start = System.currentTimeMillis();
try {
decorated.runTest();
long duration = System.currentTimeMillis() - start;
System.out.println("Test passed in " + duration + "ms");
} catch (Exception e) {
System.out.println("Test failed: " + e.getMessage());
throw e;
}
}
}
13.2 Mock对象的装饰实现
为Mock对象动态添加行为:
java复制public class VerifyingMockDecorator implements UserService {
private UserService mock;
private List<String> calledMethods = new ArrayList<>();
public VerifyingMockDecorator(UserService mock) {
this.mock = mock;
}
@Override
public void updateProfile(User user) {
calledMethods.add("updateProfile");
mock.updateProfile(user);
}
public void verifyCalled(String methodName) {
if (!calledMethods.contains(methodName)) {
throw new AssertionError("Method " + methodName + " was not called");
}
}
}
13.3 测试数据生成的装饰实现
构建灵活的数据生成器:
java复制public interface TestDataGenerator<T> {
T generate();
}
public class RandomStringGenerator implements TestDataGenerator<String> {
@Override
public String generate() {
return UUID.randomUUID().toString();
}
}
public class PrefixDecorator<T> implements TestDataGenerator<T> {
private TestDataGenerator<T> decorated;
private String prefix;
public PrefixDecorator(TestDataGenerator<T> decorated, String prefix) {
this.decorated = decorated;
this.prefix = prefix;
}
@Override
public T generate() {
if (decorated.generate() instanceof String) {
return (T) (prefix + decorated.generate());
}
return decorated.generate();
}
}
14. 装饰模式在游戏开发中的应用
游戏开发中有大量装饰模式的应用场景。我在开发游戏引擎时使用了这些技术。
14.1 游戏角色的装饰实现
为游戏角色动态添加装备和技能:
java复制public interface Character {
String getDescription();
int getAttackPower();
int getDefensePower();
}
public class BasicCharacter implements Character {
@Override
public String getDescription() {
return "冒险者";
}
@Override
public int getAttackPower() {
return 10;
}
@Override
public int getDefensePower() {
return 5;
}
}
public abstract class EquipmentDecorator implements Character {
protected Character decorated;
public EquipmentDecorator(Character decorated) {
this.decorated = decorated;
}
}
public class SwordDecorator extends EquipmentDecorator {
public SwordDecorator(Character decorated) {
super(decorated);
}
@Override
public String getDescription() {
return decorated.getDescription() + " with Sword";
}
@Override
public int getAttackPower() {
return decorated.getAttackPower() + 15;
}
}
// 使用示例
Character hero = new BasicCharacter();
hero = new SwordDecorator(hero);
hero = new ShieldDecorator(hero);
14.2 游戏特效的装饰实现
为游戏对象动态添加视觉效果:
java复制public interface GameObject {
void render();
}
public class ParticleEffectDecorator implements GameObject {
private GameObject decorated;
private ParticleSystem particles;
public ParticleEffectDecorator(GameObject decorated) {
this.decorated = decorated;
this.particles = new ParticleSystem();
}
@Override
public void render() {
decorated.render();
particles.render();
}
}
14.3 游戏AI行为的装饰实现
为AI行为动态添加策略:
java复制public interface AIBehavior {
void execute();
}
public class AggressiveDecorator implements AIBehavior {
private AIBehavior decorated;
public AggressiveDecorator(AIBehavior decorated) {
this.decorated = decorated;
}
@Override
public void execute() {
startAggressiveMode();
decorated.execute();
endAggressiveMode();
}
}
15. 装饰模式在云计算中的应用
在云原生应用开发中,装饰模式也有独特价值。我在设计云服务时应用了这些模式。
15.1 云存储客户端的装饰实现
为云存储客户端添加重试、监控等功能:
java复制public interface CloudStorage {
void upload(String key, InputStream data);
InputStream download(String key);
}
public class RetryDecorator implements CloudStorage {
private CloudStorage decorated;
private int max