Skip to content

代理模式与模板方法模式 ​


❓ 面试官:说一下代理模式?静态代理和动态代理有什么区别?【中级】 ​

频率:🔥🔥🔥🔥

💡 一句话总结(先抛结论): 代理模式就是在调用者和目标对象之间加一层“中介(代理对象)”。目的是在不修改原目标对象代码的前提下,对它进行功能增强(比如加日志、加事务、加权限校验)。

📝 详细对比实战:

1. 静态代理(比较笨重,基本不用)

  • 做法:由程序员手动写一个代理类,实现跟目标类一样的接口。在代理类的方法里调用目标类的方法,并在前后加上自己的增强逻辑。
  • 缺点:如果接口有 100 个方法,代理类就得写 100 遍增强逻辑。如果有 10 个不同的接口需要代理,就得写 10 个代理类。太麻烦了。

2. 动态代理(框架的基石,极其重要)

  • 做法:代理类不需要手写,而是在程序运行期间,由 JVM 利用反射机制动态生成在内存里的。
  • 两大流派(重点必考):
    • JDK 动态代理:Java 自带的。它要求目标类必须实现了某个接口。生成的代理类也实现了同样的接口。底层依靠 InvocationHandler 和 Proxy.newProxyInstance。
    • CGLIB 动态代理:第三方库(Spring内置了)。它不要求目标类实现接口,只要不是 final 类就行。它的原理是利用 ASM 字节码技术,动态生成一个目标类的子类作为代理。
  • Spring AOP 是用哪种?(连环追问)
    • 在 SpringBoot 2.x 以前:如果你的类实现了接口,默认用 JDK;没实现接口,就用 CGLIB。
    • 在 SpringBoot 2.x 以后:默认全部使用 CGLIB(因为 CGLIB 性能更好了,且不需要强迫写接口)。

❓ 面试官:你在项目中用过模板方法模式吗?怎么用的?【中级】 ​

频率:🔥🔥🔥🔥

💡 一句话总结(先抛结论): 模板方法模式的核心是:在父类中定义好业务的“骨架流程(模板)”,然后把某些具体的、易变的步骤延迟到子类去实现。

📝 面试高分实战场景:

"面试官您好,在我们公司的文件解析上传模块中,我大量使用了模板方法模式。"

  • 背景痛点:我们要处理别人传过来的 Excel、CSV、TXT 各种格式的财务报表。无论是哪种格式,整体的业务流程都是一模一样的:

    1. 验证文件签名和格式。
    2. 解析文件内容(这一步各不相同)。
    3. 将解析出的数据校验并入库。
    4. 记录操作日志并发送站内信通知。
  • 用模板方法重构:

    1. 建一个抽象父类 AbstractFileHandler,在里面写一个 process() 核心方法。
      java
      public void process(File file) {
          verifyFile(file); // 1. 公共方法:直接在父类写死
          List<Data> dataList = parseFile(file); // 2. 抽象方法:留给子类去实现
          saveToDb(dataList); // 3. 公共方法:父类写死
          sendNotify(); // 4. 公共方法:父类写死
      }
      // 延迟给子类的抽象方法
      protected abstract List<Data> parseFile(File file);
    2. 将 process() 方法打上 final 关键字:非常重要!这是为了防止子类乱改核心骨架流程。
    3. 建具体的子类:比如 ExcelFileHandler 继承父类,它只需要实现 parseFile() 方法,用 EasyExcel 去解析就行了。其他的校验、入库逻辑它完全不用管。

🌟 为什么这么做(加分项)? 通过模板方法模式,我们把不变的行为固化到了父类中,避免了代码的重复复制;同时把可变的行为留给了子类,极其方便日后的扩展。Spring 源码中的 JdbcTemplate 和 RestTemplate 就是极其典型的模板方法模式应用。