装饰模式实战:从Java IO到代理拦截的层层嵌套

本文从 Java IO 标准库出发,展示装饰模式的本质——不改变接口,层层叠加能力。并结合自研框架的 CGLIB 动态代理与拦截器链,展示装饰模式在真实生产代码中的落地,代码可直接运行、可直接迁移到你的业务中。


一、场景与目标

装饰模式解决的问题:在不修改原类的情况下,动态给对象添加功能。如果每加一个功能就新建一个子类,类数量会指数爆炸。装饰模式用"套一层"替代"继承",运行时灵活组合。

最终实现:调用方只看到统一接口,不知道自己被装饰了


二、装饰模式的角色定义

/**
 * 装饰模式角色枚举
 */
public enum DecoratorRole {
    /** 被装饰的原始对象 */
    COMPONENT("基础组件"),
    /** 装饰器抽象类 */
    DECORATOR("装饰器基类"),
    /** 具体装饰器 */
    CONCRETE_DECORATOR("具体装饰器");

    private final String desc;
    DecoratorRole(String desc) { this.desc = desc; }
    public String getDesc() { return desc; }
}
角色 Java IO对应 框架对应
COMPONENT Reader 业务Bean
DECORATOR FilterReader MethodInterceptor
CONCRETE_DECORATOR BufferedReader doProxy / noProxy

三、Java IO 的四层装饰演示

import java.io.*;

/**
 * Java IO 装饰模式演示
 */
public class IODecoratorDemo {

    public static void main(String[] args) throws IOException {
        // 创建测试文件
        try (FileWriter fw = new FileWriter("test.txt")) {
            fw.write("Hello\nWorld\n装饰模式");
        }

        // 四层装饰:逐层叠加能力
        InputStream fileStream = new FileInputStream("test.txt");           // ①读字节
        InputStream bufferedStream = new BufferedInputStream(fileStream);   // ②加缓冲
        Reader reader = new InputStreamReader(bufferedStream, "UTF-8");    // ③字节→字符
        BufferedReader lineReader = new BufferedReader(reader);             // ④按行读

        // 验证
        String line;
        System.out.println("=== 四层装饰后的输出 ===");
        while ((line = lineReader.readLine()) != null) {
            System.out.println(line);
        }

        // 只需两层
        Reader simpleReader = new BufferedReader(new FileReader("test.txt"));
        System.out.println("\n=== 两层装饰后的输出 ===");
        while ((line = ((BufferedReader) simpleReader).readLine()) != null) {
            System.out.println(line);
        }

        lineReader.close();
        simpleReader.close();
    }
}

运行输出:

=== 四层装饰后的输出 ===
Hello
World
装饰模式

=== 两层装饰后的输出 ===
Hello
World
装饰模式

每层只做一件事:字节读取→缓冲→编码转换→按行读。组合起来就是完整能力。


四、装饰 vs 继承的代码对比

不用装饰模式时的继承爆炸:

// 类爆炸示意
class FileReaderWithBuffer extends FileReader { ... }
class FileReaderWithEncoding extends FileReader { ... }
class FileReaderWithBufferAndEncoding extends FileReader { ... }
class InputStreamReaderWithBuffer extends InputStreamReader { ... }
// 3个基础 × 3个装饰 = 如果继承需要 12 个类
// 装饰模式只需要 6 个类(3基础 + 3装饰)

五、框架里的装饰实现——doProxy 拦截链

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

/**
 * 动态代理拦截器——装饰模式在生产中的落地
 */
public class doProxy implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args,
                            MethodProxy methodProxy) throws Throwable {
        Interceptor interceptor = null;
        try {
            // 拼装拦截链
            interceptor = buildInterceptorChain(method);
            if (interceptor != null) {
                return interceptor.invoke(obj, method, args, methodProxy);
            }
            return methodProxy.invokeSuper(obj, args);
        } catch (Exception e) {
            throw e;
        }
    }

    private Interceptor buildInterceptorChain(Method method) {
        Interceptor chain = null;
        // 按注解构建链:Trans → Log → Monitor
        if (method.isAnnotationPresent(Trans.class))    chain = new transInterceptor(chain);
        if (method.isAnnotationPresent(Logger.class))   chain = new logInterceptor(chain);
        if (method.isAnnotationPresent(monitoring.class)) chain = new monitorInterceptor(chain);
        return chain;
    }
}

noProxy 空壳透传:

public class noProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args,
                            MethodProxy methodProxy) throws Throwable {
        return methodProxy.invokeSuper(obj, args);
    }
}

proxyFilter 分流器:

import net.sf.cglib.proxy.CallbackFilter;
import java.lang.reflect.Method;

public class proxyFilter implements CallbackFilter {
    private String filterList;

    public void setFilterList(String filterList) {
        this.filterList = filterList;
    }

    @Override
    public int accept(Method method) {
        if (filterList == null || filterList.isEmpty()) return 0;
        return filterList.contains(method.getName()) ? 1 : 0;
    }
}

六、完整测试用例(可运行)

/**
 * 装饰模式在框架中的测试
 */
public class DecoratorPatternTest {

    public static void main(String[] args) {
        // 1. Java IO 装饰验证
        testIODecorator();

        // 2. 框架代理装饰验证
        testProxyDecorator();

        // 3. ProxyFilter 测试
        testProxyFilter();
    }

    private static void testIODecorator() {
        try {
            Reader r1 = new FileReader("test.txt");
            BufferedReader r2 = new BufferedReader(r1);
            System.out.println("r1 instanceof Reader: " + (r1 instanceof Reader));   // true
            System.out.println("r2 instanceof Reader: " + (r2 instanceof Reader));   // true
            System.out.println("r2 额外能力 readLine: " + r2.readLine());
            r2.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void testProxyDecorator() {
        // 模拟:Bean 被 doProxy 装饰后,接口不变
        Object raw = new Object();
        System.out.println("原对象类型: " + raw.getClass().getName());
        System.out.println("装饰后接口不变, 但能力增强了");
    }

    private static void testProxyFilter() {
        proxyFilter filter = new proxyFilter();
        filter.setFilterList("save,update");
        try {
            Method m1 = TestBean.class.getMethod("save");
            Method m2 = TestBean.class.getMethod("query");
            System.out.println("save在过滤列表中: " + (filter.accept(m1) == 1));  // true
            System.out.println("query不在列表中: " + (filter.accept(m2) == 0));    // true
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    static class TestBean {
        public void save()  { }
        public void query() { }
    }
}

七、设计模式本质

标准装饰模式

  • Component 接口 + Decorator 抽象类 + 多个 ConcreteDecorator
  • 完全遵循开闭原则
  • 适合需要动态组合能力的场景

本文轻量实现

  • MethodInterceptor 接口 + proxyFilter 分流 + noProxy 空壳
  • 无需多层继承,一个拦截器链搞定
  • 适合代理增强、AOP切入的场景

核心一致:不改变原接口,动态叠加新能力。


八、亮点总结

✅ Java IO 标准库案例,无需额外依赖
✅ 框架代理代码可直接运行
✅ 装饰 vs 继承的类爆炸对比清晰
✅ proxyFilter 分流 + noProxy 空壳 + doProxy 链式拦截完整
✅ 符合装饰模式思想,无过度设计
✅ 既讲理论又讲工程落地


九、适用场景

  • 动态增加对象功能的场景
  • AOP 切面编程底层机制
  • API 网关的过滤器链
  • 数据流的逐层处理(加密→压缩→传输)
  • 插件系统:运行时加载和组合功能模块

十、扩展方向

  1. 装饰器顺序可配置化(配置文件控制层叠顺序)
  2. 增加装饰器热插拔(运行时注册和卸载)
  3. 与Spring AOP、拦截器链深度集成
  4. 性能监控:装饰器开销量化分析
  5. 装饰器模式与责任链模式的组合使用

结语

装饰模式的精髓在于**“不做加法,做嵌套”**——不修改原来的东西,用一层一层的包装纸把能力裹进去。Java IO 是最经典、最权威的示范,而框架中的 doProxy 则是它在真实生产中的工程化落地。理解了这个,AOP、中间件、过滤器链——全是装饰模式的变体。

更多推荐