网站Logo Ilren 小记

Java设计模式-装饰器模式

jack
6
2023-05-05

模式简介
装饰器模式是一种结构型设计模式,允许通过将对象放入包含行为的特殊封装对象中来为原对象动态添加新的行为。
就像给礼物层层包装一样,每层包装都能添加新的装饰效果,而不改变礼物本身。

📦 应用场景

  • Java I/O流体系(BufferedInputStream等)

  • 前端组件样式叠加

  • 权限校验链

  • 日志增强

  • Spring AOP中的拦截器

  • GUI组件边框/滚动条添加

🧠 核心实现思路

  1. 组件接口:定义原始对象和装饰器的共同接口

  2. 具体组件:实现基础功能的核心类

  3. 装饰器基类:持有组件引用并实现组件接口

  4. 具体装饰器:添加特定增强功能

🧱 装饰器模式的多种实现方式

1. 经典实现(Java I/O风格)

// 组件接口
interface Coffee {
    double getCost();
    String getDescription();
}

// 具体组件
class SimpleCoffee implements Coffee {
    public double getCost() { return 1.0; }
    public String getDescription() { return "普通咖啡"; }
}

// 装饰器基类
abstract class CoffeeDecorator implements Coffee {
    protected final Coffee decoratedCoffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }
}

// 具体装饰器
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    public double getCost() {
        return decoratedCoffee.getCost() + 0.5;
    }
    
    public String getDescription() {
        return decoratedCoffee.getDescription() + ",加牛奶";
    }
}

2. Lambda实现(轻量级装饰)

// 函数式接口
interface TextProcessor {
    String process(String text);
}

// 装饰器工具类
class TextDecorators {
    public static TextProcessor boldDecorator(TextProcessor processor) {
        return text -> "<b>" + processor.process(text) + "</b>";
    }
    
    public static TextProcessor colorDecorator(String color, TextProcessor processor) {
        return text -> String.format("<span style='color:%s'>%s</span>", 
                                  color, processor.process(text));
    }
}

// 使用示例
TextProcessor processor = TextDecorators.colorDecorator("red",
                      TextDecorators.boldDecorator(
                          text -> text.toUpperCase()));
String result = processor.process("hello"); // 输出红色加粗HELLO

3. Spring AOP实现

@Aspect
@Component
class LoggingAspect {
    
    @Around("execution(* com.example.service.*.*(..))")
    public Object logMethodCall(ProceedingJoinPoint pjp) throws Throwable {
        // 前置增强
        System.out.println("调用方法: " + pjp.getSignature());
        
        // 执行原方法
        Object result = pjp.proceed();
        
        // 后置增强
        System.out.println("方法返回: " + result);
        return result;
    }
}

💎 最佳实践推荐

透明性装饰器(保持接口一致)

// 使用继承保证类型透明
class TransparentDecorator extends SomeComponent {
    private final SomeComponent target;
    
    @Override
    public void operation() {
        // 前置处理
        target.operation();
        // 后置处理
    }
}

组合式装饰器(Builder风格)

class Pizza {
    private List<String> toppings = new ArrayList<>();
    
    public Pizza addTopping(String topping) {
        toppings.add(topping);
        return this;
    }
    
    public void bake() {
        System.out.println("烘焙披萨:" + String.join(",", toppings));
    }
}

// 使用链式调用
new Pizza()
    .addTopping("芝士")
    .addTopping("蘑菇")
    .bake();

💣 常见问题与解决方案

问题1:装饰器 vs 继承?

解决方案

  • 继承是静态扩展,装饰器是动态组合

  • 优先使用装饰器(更灵活,避免类爆炸)

问题2:多层装饰性能问题?

解决方案

  • 控制装饰层数(通常不超过5层)

  • 对高频操作使用缓存

问题3:如何保持装饰顺序?

解决方案

  • 使用Builder模式控制装饰流程

  • 定义装饰优先级注解

📊 模式对比

实现方式

优点

缺点

适用场景

经典继承实现

类型安全

类层次复杂

需要严格类型检查

组合对象

灵活扩展

运行时类型丢失

动态功能组合

AOP装饰

非侵入式

调试困难

横切关注点处理

📚 实际应用案例

  1. Java I/O流体系

    // 多层装饰示例
    InputStream in = new BufferedInputStream(
                    new GZIPInputStream(
                    new FileInputStream("test.gz")));
  2. Web拦截器

    // Spring MVC拦截器链
    public class LogInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, 
                              HttpServletResponse response, 
                              Object handler) {
            // 装饰请求处理逻辑
            return true;
        }

🎯 总结建议

  1. 优先选择:组合优于继承

  2. 性能注意:避免过深装饰层次

  3. 设计原则:符合开闭原则(对扩展开放,对修改关闭)

  4. 适用场景:当需要动态、透明地添加功能时

  5. 避免滥用:简单扩展可直接使用子类

动物装饰