1. 从咖啡店案例看装饰器模式的价值
在软件开发中,我们经常会遇到需要动态扩展对象功能的需求。想象一下咖啡店的场景:顾客点了一杯美式咖啡,可能还需要加糖、加奶、加奶油等各种配料。如果为每种可能的组合都创建一个子类,代码很快就会变得臃肿不堪。这正是装饰器模式(Decorator Pattern)大显身手的地方。
装饰器模式属于结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
提示:装饰器模式与继承最大的区别在于,继承是静态扩展,而装饰器是动态扩展。这在需要灵活组合功能时尤为重要。
在Java中,装饰器模式通过以下方式实现:
- 定义一个接口或抽象类作为组件(Component)
- 创建具体组件(ConcreteComponent)实现基础功能
- 创建装饰器抽象类(Decorator)实现相同接口并持有组件引用
- 创建具体装饰器(ConcreteDecorator)添加额外功能
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 咖啡店案例的代码实现
2.1 基础结构设计
我们先定义饮料的抽象类和具体实现:
java复制// 饮料抽象类(Component)
public abstract class Beverage {
protected String description = "Unknown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
// 具体饮料(ConcreteComponent)
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
public double cost() {
return 1.99;
}
}
public class HouseBlend extends Beverage {
public HouseBlend() {
description = "House Blend Coffee";
}
public double cost() {
return 0.89;
}
}
2.2 装饰器实现
接下来实现调料装饰器:
java复制// 调料装饰器抽象类(Decorator)
public abstract class CondimentDecorator extends Beverage {
protected Beverage beverage;
public abstract String getDescription();
}
// 具体装饰器(ConcreteDecorator)
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
return beverage.cost() + 0.20;
}
}
public class Whip extends CondimentDecorator {
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
public double cost() {
return beverage.cost() + 0.10;
}
}
2.3 客户端使用示例
java复制public class CoffeeShop {
public static void main(String[] args) {
// 订一杯Espresso,不加调料
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" + beverage.cost());
// 订一杯HouseBlend,加双份Mocha和Whip
Beverage beverage2 = new HouseBlend();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
}
}
输出结果:
code复制Espresso $1.99
House Blend Coffee, Mocha, Mocha, Whip $1.39
3. 装饰器模式深度解析
3.1 设计原则体现
装饰器模式完美体现了以下几个面向对象设计原则:
-
开闭原则(OCP):对扩展开放,对修改关闭。我们可以通过添加新的装饰器来扩展功能,而不需要修改现有代码。
-
单一职责原则(SRP):每个装饰器类只负责一个特定的功能,如Mocha只负责添加摩卡风味,Whip只负责添加奶油。
-
组合优于继承:通过对象组合的方式动态添加功能,避免了类爆炸问题。
3.2 与类似模式的对比
-
与适配器模式的区别:
- 适配器改变接口以适配客户端
- 装饰器保持接口不变,增强功能
-
与代理模式的区别:
- 代理控制对对象的访问
- 装饰器增强对象的功能
-
与继承的区别:
- 继承是编译时静态行为
- 装饰是运行时动态行为
3.3 性能考量
虽然装饰器模式提供了灵活性,但也需要注意:
-
对象数量:多层装饰会导致创建大量小对象,可能影响性能
-
调试复杂性:由于对象被多层包装,调试时可能需要追踪多个层次
-
类型检查:使用instanceof检查对象类型时可能不如继承直观
4. 实际项目中的代码重构案例
4.1 重构前的问题代码
假设我们有一个文件处理系统,最初使用继承实现:
java复制public class BasicFileProcessor {
public void process() {
// 基础文件处理逻辑
}
}
public class CompressedFileProcessor extends BasicFileProcessor {
@Override
public void process() {
super.process();
// 压缩处理逻辑
}
}
public class EncryptedFileProcessor extends BasicFileProcessor {
@Override
public void process() {
super.process();
// 加密处理逻辑
}
}
// 如果需要同时压缩和加密怎么办?
// 需要创建CompressedAndEncryptedFileProcessor类
// 这样会导致类爆炸问题
4.2 使用装饰器模式重构
重构后的代码结构:
java复制// 组件接口
public interface FileProcessor {
void process();
}
// 具体组件
public class BasicFileProcessor implements FileProcessor {
public void process() {
// 基础文件处理逻辑
}
}
// 装饰器抽象类
public abstract class FileProcessorDecorator implements FileProcessor {
protected FileProcessor fileProcessor;
public FileProcessorDecorator(FileProcessor fileProcessor) {
this.fileProcessor = fileProcessor;
}
public void process() {
fileProcessor.process();
}
}
// 具体装饰器
public class CompressionDecorator extends FileProcessorDecorator {
public CompressionDecorator(FileProcessor fileProcessor) {
super(fileProcessor);
}
@Override
public void process() {
super.process();
compress();
}
private void compress() {
// 压缩逻辑
}
}
public class EncryptionDecorator extends FileProcessorDecorator {
public EncryptionDecorator(FileProcessor fileProcessor) {
super(fileProcessor);
}
@Override
public void process() {
super.process();
encrypt();
}
private void encrypt() {
// 加密逻辑
}
}
4.3 客户端使用
java复制public class Client {
public static void main(String[] args) {
// 基础处理
FileProcessor processor = new BasicFileProcessor();
processor.process();
// 压缩处理
FileProcessor compressed = new CompressionDecorator(processor);
compressed.process();
// 加密且压缩处理
FileProcessor encryptedAndCompressed = new EncryptionDecorator(
new CompressionDecorator(processor)
);
encryptedAndCompressed.process();
}
}
5. 装饰器模式的最佳实践与陷阱
5.1 最佳实践
-
接口设计:装饰器和被装饰对象应实现相同的接口,这是装饰器模式的核心
-
透明性:装饰器应该对被装饰对象完全透明,客户端不应感知装饰器的存在
-
小型装饰器:每个装饰器应该只负责一个小的功能点,保持职责单一
-
装饰顺序:注意装饰器的顺序可能影响最终结果,设计时要考虑这一点
5.2 常见陷阱
-
过度装饰:装饰层数过多会导致系统复杂度和内存使用增加
-
与工厂模式结合:当装饰逻辑复杂时,考虑使用工厂模式创建装饰链
-
性能敏感场景:在性能关键路径上慎用多层装饰,可能带来性能损耗
-
equals/hashCode:装饰器可能破坏对象的相等性判断,需要特别注意
5.3 Java标准库中的应用
Java I/O流是装饰器模式的经典实现:
java复制// FileInputStream是被装饰的组件
InputStream in = new FileInputStream("test.txt");
// BufferedInputStream是装饰器
in = new BufferedInputStream(in);
// DataInputStream是另一个装饰器
in = new DataInputStream(in);
其他应用场景:
- Java Collections的checkedXXX、synchronizedXXX等方法
- Servlet API中的HttpServletRequestWrapper
- Spring框架中的各种Wrapper类
6. 装饰器模式面试要点
6.1 常见面试问题
- 装饰器模式和继承有什么区别?
- 装饰器模式的优缺点是什么?
- 如何在项目中实际应用装饰器模式?
- 装饰器模式与代理模式的区别?
- Java中哪些地方使用了装饰器模式?
6.2 面试回答技巧
当被问到装饰器模式时,可以按照以下结构回答:
- 定义:首先给出装饰器模式的标准定义
- 目的:说明它解决什么问题(动态扩展功能)
- 结构:描述关键角色(Component、ConcreteComponent、Decorator、ConcreteDecorator)
- 示例:给出一个简单示例(如咖啡店案例)
- 对比:与类似模式(如代理、适配器)的区别
- 应用:在实际项目或JDK中的应用
- 评价:优缺点和适用场景
6.3 代码实现考察
面试官可能会要求现场实现装饰器模式。记住以下要点:
- 定义组件接口
- 实现具体组件
- 创建装饰器抽象类(实现组件接口并持有组件引用)
- 实现具体装饰器
- 展示客户端如何使用
7. 装饰器模式的现代应用与变体
7.1 函数式编程中的装饰器
在Java 8+中,我们可以用函数式风格实现装饰器:
java复制import java.util.function.Function;
public class FunctionalDecorator {
public static void main(String[] args) {
Function<String, String> simpleGreeting = name -> "Hello, " + name;
// 装饰器函数
Function<String, String> decoratedGreeting = simpleGreeting
.andThen(s -> s + "!") // 添加感叹号
.andThen(s -> s.toUpperCase()); // 转为大写
System.out.println(decoratedGreeting.apply("John"));
// 输出: HELLO, JOHN!
}
}
7.2 与Lambda表达式结合
java复制public class CoffeeShopLambda {
interface Coffee {
String getDescription();
double getCost();
default Coffee with(CoffeeDecorator decorator) {
return decorator.decorate(this);
}
}
interface CoffeeDecorator {
Coffee decorate(Coffee coffee);
}
public static void main(String[] args) {
CoffeeDecorator addMocha = coffee -> new Coffee() {
public String getDescription() {
return coffee.getDescription() + ", Mocha";
}
public double getCost() {
return coffee.getCost() + 0.2;
}
};
CoffeeDecorator addWhip = coffee -> new Coffee() {
public String getDescription() {
return coffee.getDescription() + ", Whip";
}
public double getCost() {
return coffee.getCost() + 0.1;
}
};
Coffee myCoffee = new Coffee() {
public String getDescription() { return "Espresso"; }
public double getCost() { return 1.99; }
}.with(addMocha).with(addWhip);
System.out.println(myCoffee.getDescription() + " - $" + myCoffee.getCost());
}
}
7.3 响应式编程中的装饰器
在响应式流(如Reactor)中,装饰器模式被广泛使用:
java复制import reactor.core.publisher.Flux;
public class ReactiveDecorator {
public static void main(String[] args) {
Flux<Integer> numbers = Flux.range(1, 5);
// 添加装饰(操作符)
Flux<Integer> processed = numbers
.map(i -> i * 2) // 装饰1:转换
.filter(i -> i > 3) // 装饰2:过滤
.doOnNext(i -> System.out.println("Value: " + i)); // 装饰3:副作用
processed.subscribe();
}
}
8. 设计模式组合应用
8.1 装饰器与工厂模式结合
当装饰逻辑复杂时,可以使用工厂模式创建装饰链:
java复制public class BeverageFactory {
public static Beverage createCoffee(String type, List<String> condiments) {
Beverage beverage;
switch (type) {
case "espresso": beverage = new Espresso(); break;
case "houseblend": beverage = new HouseBlend(); break;
default: throw new IllegalArgumentException("Unknown coffee type");
}
for (String condiment : condiments) {
switch (condiment) {
case "mocha": beverage = new Mocha(beverage); break;
case "whip": beverage = new Whip(beverage); break;
// 其他调料...
}
}
return beverage;
}
}
8.2 装饰器与策略模式结合
策略模式可以动态改变装饰行为:
java复制public interface PricingStrategy {
double apply(double basePrice);
}
public class HolidayPricing implements PricingStrategy {
public double apply(double basePrice) {
return basePrice * 1.2; // 节假日加价20%
}
}
public class DiscountPricing implements PricingStrategy {
public double apply(double basePrice) {
return basePrice * 0.9; // 打9折
}
}
public class PricingDecorator extends CondimentDecorator {
private PricingStrategy strategy;
public PricingDecorator(Beverage beverage, PricingStrategy strategy) {
super(beverage);
this.strategy = strategy;
}
public double cost() {
return strategy.apply(beverage.cost());
}
}
9. 测试装饰器模式
9.1 单元测试策略
测试装饰器时需要注意:
- 单独测试每个装饰器
- 测试装饰器组合
- 验证装饰顺序的影响
示例测试:
java复制public class DecoratorTest {
@Test
public void testEspressoWithMocha() {
Beverage beverage = new Espresso();
beverage = new Mocha(beverage);
assertEquals("Espresso, Mocha", beverage.getDescription());
assertEquals(2.19, beverage.cost(), 0.01);
}
@Test
public void testDecoratorOrder() {
Beverage b1 = new Whip(new Mocha(new HouseBlend()));
Beverage b2 = new Mocha(new Whip(new HouseBlend()));
// 顺序不同,描述不同,但价格相同
assertNotEquals(b1.getDescription(), b2.getDescription());
assertEquals(b1.cost(), b2.cost(), 0.01);
}
}
9.2 模拟与依赖注入
在复杂场景中,可以使用Mock框架测试装饰器:
java复制@ExtendWith(MockitoExtension.class)
public class FileProcessorTest {
@Mock
FileProcessor mockProcessor;
@Test
public void testCompressionDecorator() {
CompressionDecorator decorator = new CompressionDecorator(mockProcessor);
decorator.process();
verify(mockProcessor).process();
// 验证压缩逻辑...
}
}
10. 装饰器模式在架构设计中的应用
10.1 中间件设计
Web框架中的中间件本质上是装饰器模式的应用:
java复制public interface Handler {
void handle(Request request, Response response);
}
public class LoggerMiddleware implements Handler {
private Handler next;
public LoggerMiddleware(Handler next) {
this.next = next;
}
public void handle(Request request, Response response) {
System.out.println("Request: " + request);
next.handle(request, response);
System.out.println("Response: " + response);
}
}
public class AuthMiddleware implements Handler {
private Handler next;
public AuthMiddleware(Handler next) {
this.next = next;
}
public void handle(Request request, Response response) {
if (checkAuth(request)) {
next.handle(request, response);
} else {
response.setStatus(401);
}
}
private boolean checkAuth(Request request) {
// 验证逻辑...
}
}
10.2 微服务中的装饰器
在微服务架构中,可以使用装饰器模式实现:
- 断路器模式
- 重试逻辑
- 缓存层
- 监控和日志
java复制public interface UserService {
User getUser(String id);
}
public class CircuitBreakerUserService implements UserService {
private UserService wrapped;
private CircuitBreaker breaker;
public User getUser(String id) {
return breaker.execute(() -> wrapped.getUser(id));
}
}
public class RetryUserService implements UserService {
private UserService wrapped;
private RetryTemplate retry;
public User getUser(String id) {
return retry.execute(ctx -> wrapped.getUser(id));
}
}
11. 性能优化与高级技巧
11.1 减少对象创建
多层装饰会创建大量小对象,可以通过以下方式优化:
- 对象池:重用装饰器对象
- 不可变装饰器:适合线程安全场景
- 延迟初始化:推迟装饰器的实际创建
java复制public class CachedDecorator implements Beverage {
private Beverage beverage;
private String cachedDescription;
private Double cachedCost;
public CachedDecorator(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
if (cachedDescription == null) {
cachedDescription = beverage.getDescription();
}
return cachedDescription;
}
public double cost() {
if (cachedCost == null) {
cachedCost = beverage.cost();
}
return cachedCost;
}
}
11.2 动态代理实现
使用Java动态代理实现装饰器:
java复制public class DynamicDecorator {
interface Coffee {
String getDescription();
double getCost();
}
static class SimpleCoffee implements Coffee {
public String getDescription() { return "Coffee"; }
public double getCost() { return 1.0; }
}
public static void main(String[] args) {
Coffee coffee = new SimpleCoffee();
Coffee proxy = (Coffee) Proxy.newProxyInstance(
Coffee.class.getClassLoader(),
new Class[] { Coffee.class },
(proxyObj, method, methodArgs) -> {
if (method.getName().equals("getDescription")) {
return method.invoke(coffee, methodArgs) + " (enhanced)";
}
if (method.getName().equals("getCost")) {
return (double) method.invoke(coffee, methodArgs) + 0.5;
}
return method.invoke(coffee, methodArgs);
}
);
System.out.println(proxy.getDescription()); // Coffee (enhanced)
System.out.println(proxy.getCost()); // 1.5
}
}
12. 设计模式演进与替代方案
12.1 装饰器模式的局限性
- 复杂性:多层装饰会增加系统复杂度
- 调试困难:错误可能发生在任何装饰层
- 过度使用:不是所有场景都需要动态扩展
12.2 现代替代方案
- 组合API:如React Hooks、Vue Composition API
- 切面编程(AOP):通过切面实现横切关注点
- 函数组合:在函数式编程中替代装饰器
java复制// 函数组合替代装饰器
public class FunctionalComposition {
static Function<String, String> addHeader = text -> "Header\n" + text;
static Function<String, String> addFooter = text -> text + "\nFooter";
static Function<String, String> transform = addHeader.andThen(addFooter);
public static void main(String[] args) {
System.out.println(transform.apply("Content"));
}
}
13. 项目实战:电商促销系统
13.1 需求分析
电商促销系统需要支持:
- 多种折扣类型(满减、百分比、固定金额)
- 折扣叠加(如VIP折扣+节日折扣)
- 折扣优先级控制
13.2 装饰器实现
java复制public interface Order {
double getTotal();
String getDescription();
}
public class BasicOrder implements Order {
private double amount;
public BasicOrder(double amount) {
this.amount = amount;
}
public double getTotal() {
return amount;
}
public String getDescription() {
return String.format("商品总额: %.2f", amount);
}
}
public abstract class OrderDecorator implements Order {
protected Order decoratedOrder;
public OrderDecorator(Order decoratedOrder) {
this.decoratedOrder = decoratedOrder;
}
public double getTotal() {
return decoratedOrder.getTotal();
}
public String getDescription() {
return decoratedOrder.getDescription();
}
}
public class PercentageDiscount extends OrderDecorator {
private double percentage;
public PercentageDiscount(Order decoratedOrder, double percentage) {
super(decoratedOrder);
this.percentage = percentage;
}
public double getTotal() {
double base = super.getTotal();
return base * (1 - percentage/100);
}
public String getDescription() {
return super.getDescription() +
String.format("\n%d%%折扣: -%.2f",
(int)percentage,
super.getTotal() * percentage/100);
}
}
public class FixedAmountDiscount extends OrderDecorator {
private double amount;
public FixedAmountDiscount(Order decoratedOrder, double amount) {
super(decoratedOrder);
this.amount = amount;
}
public double getTotal() {
return Math.max(0, super.getTotal() - amount);
}
public String getDescription() {
return super.getDescription() +
String.format("\n固定折扣: -%.2f", amount);
}
}
13.3 客户端使用
java复制public class PromotionSystem {
public static void main(String[] args) {
Order order = new BasicOrder(1000);
// 应用20%折扣
order = new PercentageDiscount(order, 20);
// 再应用100元固定折扣
order = new FixedAmountDiscount(order, 100);
System.out.println(order.getDescription());
System.out.println("最终金额: " + order.getTotal());
}
}
输出:
code复制商品总额: 1000.00
20%折扣: -200.00
固定折扣: -100.00
最终金额: 700.0
14. 设计模式可视化工具
14.1 PlantUML类图
plantuml复制@startuml
abstract class Beverage {
+getDescription(): String
+cost(): double
}
class Espresso {
+cost(): double
}
class HouseBlend {
+cost(): double
}
abstract class CondimentDecorator {
-beverage: Beverage
+getDescription(): String
}
class Mocha {
+cost(): double
+getDescription(): String
}
class Whip {
+cost(): double
+getDescription(): String
}
Beverage <|-- Espresso
Beverage <|-- HouseBlend
Beverage <|-- CondimentDecorator
CondimentDecorator <|-- Mocha
CondimentDecorator <|-- Whip
@enduml
14.2 序列图示例
plantuml复制@startuml
participant Client
participant "Mocha" as M
participant "Whip" as W
participant "HouseBlend" as HB
Client -> HB : new HouseBlend()
Client -> M : new Mocha(HB)
Client -> W : new Whip(M)
Client -> W : getDescription()
W -> M : getDescription()
M -> HB : getDescription()
HB --> M : "House Blend Coffee"
M --> W : "House Blend Coffee, Mocha"
W --> Client : "House Blend Coffee, Mocha, Whip"
@enduml
15. 代码质量与重构指标
15.1 重构指标
使用装饰器模式重构后,可以评估以下指标:
- 类数量:虽然装饰器会增加类数量,但避免了类爆炸
- 耦合度:降低了具体组件与扩展功能的耦合
- 可维护性:更容易添加新功能而不影响现有代码
- 单元测试:每个装饰器可以独立测试
15.2 代码异味检测
以下代码异味提示可能需要装饰器模式:
- 过长的条件语句:根据不同条件添加不同功能
- 类爆炸:大量子类仅为了组合不同功能
- 重复代码:相似功能分散在多个类中
15.3 静态分析工具
使用SonarQube、Checkstyle等工具可以检测:
- God Class:过大类可能需要用装饰器拆分
- Feature Envy:功能过于依赖其他类的数据
- Duplicated Code:重复逻辑可用装饰器抽象
16. 团队协作与设计评审
16.1 设计评审要点
评审装饰器模式实现时关注:
- 接口设计:装饰器和组件接口是否合理
- 装饰粒度:每个装饰器是否职责单一
- 性能影响:多层装饰是否会影响性能
- 线程安全:装饰器是否考虑并发场景
16.2 文档规范
在文档中应明确:
- 装饰器列表:所有可用装饰器及其功能
- 组合规则:哪些装饰器可以组合,顺序是否重要
- 示例代码:典型使用场景示例
- 性能警告:多层装饰的性能影响
16.3 团队协作建议
- 命名约定:统一装饰器命名(如XXXDecorator)
- 包结构:合理组织装饰器类(如decorator包)
- 代码审查:特别注意装饰器的线程安全性
- 文档更新:添加新装饰器时同步更新文档
17. 设计模式与领域驱动设计
17.1 DDD中的装饰器
在领域驱动设计中,装饰器模式可用于:
- 领域服务增强:如日志、缓存、重试等横切关注点
- 值对象装饰:动态添加验证或转换逻辑
- 仓储实现:增强基础仓储功能(如缓存仓储)
java复制public interface OrderRepository {
Order findById(String id);
}
public class CachingOrderRepository implements OrderRepository {
private OrderRepository delegate;
private Cache cache;
public Order findById(String id) {
Order order = cache.get(id);
if (order == null) {
order = delegate.findById(id);
cache.put(id, order);
}
return order;
}
}
17.2 防腐层实现
装饰器可用于实现防腐层(ACL):
java复制public interface ExternalPaymentService {
PaymentResult charge(PaymentRequest request);
}
public class PaymentServiceAdapter implements PaymentService {
private ExternalPaymentService externalService;
public PaymentResult pay(Order order) {
PaymentRequest request = convert(order);
PaymentResult result = externalService.charge(request);
return adapt(result);
}
// 转换方法...
}
18. 设计模式与云原生
18.1 云原生中的装饰器
云原生架构中的装饰器模式应用:
- 断路器:装饰服务调用添加熔断逻辑
- 重试机制:装饰服务调用添加重试
- 分布式追踪:装饰请求添加追踪信息
- 服务网格:Sidecar代理本质上是网络装饰器
java复制public class CircuitBreakerHttpClient implements HttpClient {
private HttpClient delegate;
private CircuitBreaker breaker;
public HttpResponse execute(HttpRequest request) {
return breaker.execute(() -> delegate.execute(request));
}
}
18.2 Serverless中的装饰器
Serverless函数中的装饰器应用:
- 输入验证:装饰函数入口验证参数
- 输出转换:装饰函数输出转换格式
- 错误处理:装饰函数添加统一错误处理
- 日志记录:装饰函数添加请求日志
typescript复制// TypeScript示例
function logWrapper(fn: Function) {
return async (event: any, context: any) => {
console.log('Request:', event);
const result = await fn(event, context);
console.log('Response:', result);
return result;
};
}
const handler = logWrapper(async (event) => {
// 业务逻辑...
});
19. 设计模式演进趋势
19.1 函数式风格的兴起
传统装饰器模式正在向函数式风格演进:
- 高阶函数:替代装饰器类
- 函数组合:替代多层装饰
- 不变性:避免装饰器带来的副作用
kotlin复制// Kotlin示例
fun <T> logDecorator(fn: (T) -> Unit): (T) -> Unit {
return { input ->
println("Calling with $input")
fn(input)
println("Call completed")
}
}
val decoratedFn = logDecorator { x: Int -> println(x * 2) }
decoratedFn(5) // 输出: Calling with 5 \n 10 \n Call completed
19.2 响应式编程的影响
响应式流中的操作符本质上是装饰器:
java复制// Reactor示例
Flux<Integer> flux = Flux.just(1, 2, 3)
.map(i -> i * 2) // 装饰1
.filter(i -> i > 3) // 装饰2
.doOnNext(System.out::println); // 装饰3
19.3 微服务与装饰器
微服务架构中装饰器的新应用:
- 服务网格:网络调用的装饰
- API网关:请求响应的装饰
- Sidecar模式:进程间通信的装饰
20. 个人经验与建议
在实际项目中使用装饰器模式时,我有以下几点体会:
-
明确边界:装饰器应该只负责"增强"功能,而不是改变核心逻辑。如果发现装饰器在修改核心行为,可能需要重新考虑设计。
-
控制层数:3-4层装饰还能保持可读性,超过这个数量就要考虑是否过度设计了。我曾经维护过一个7层装饰的代码,调试起来非常痛苦。
-
文档注释:每个装饰器都应该有清晰的文档说明它的作用和预期行为。特别是当装饰器有顺序依赖时,一定要明确说明。
-
性能测试:在性能敏感的场景,一定要对装饰后的代码进行性能测试。我曾经遇到过一个简单的缓存装饰器因为没考虑并发反而降低了性能。
-
与团队沟通:装饰器模式虽然强大,但不是所有开发人员都熟悉。在团队中引入这个模式时,要做好知识共享和代码评审。
最后一个小技巧:在Java中,可以使用注解处理器自动生成装饰器类,减少样板代码。例如:
java复制@DecoratorFor(Beverage.class)
public class Mocha {
private Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
return beverage.cost() + 0.20;
}
}
