Skip to content

设计模式高频题

面试只盯着最高频的几个模式问:单例、工厂、观察者、策略、代理、装饰器。能画出结构图 + 说出真实使用场景才算过关。

Q1: 手写一个线程安全的单例模式 「🟡 中级」

考察点:并发安全意识、对 double-check 细节的掌握。

参考答案(Java 双重检查锁):

java
public class Singleton {
    // volatile 禁止指令重排,防止拿到半初始化对象
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {                 // 第一次检查,避免每次加锁
            synchronized (Singleton.class) {
                if (instance == null) {         // 第二次检查,防止重复创建
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

要点:new 分三步(分配内存→初始化→引用赋值),重排后其他线程可能拿到未初始化的对象,所以必须 volatile

追问延伸

  • 静态内部类和枚举实现单例各有什么优缺点?
  • 序列化、反射能破坏单例吗?怎么防?

Q2: 工厂模式的三种形态分别解决什么问题? 「🟡 中级」

考察点:创建型模式的理解深度。

参考答案

  • 简单工厂:一个工厂类按参数创建不同产品;违反开闭原则,但产品少时够用。
  • 工厂方法:每个产品对应一个工厂子类,新增产品只需新增工厂,符合开闭。
  • 抽象工厂:创建"一族"相关产品(如同时造 Mac 的键盘和鼠标),保证产品之间的配套关系。
  • 实际应用:Calendar.getInstance()、Spring 的 BeanFactory、MyBatis 的 SqlSessionFactory

追问延伸

  • Spring 容器算哪种工厂?(超级工厂 + 单例/原型管理)
  • 工厂模式和建造者模式的取舍?

Q3: 观察者模式的应用场景? 「🟡 中级」

考察点:行为型模式 + 解耦思想。

参考答案

  • 定义一对多依赖:一个对象状态变化时,所有依赖它的观察者自动收到通知。
  • 典型场景:事件系统、消息订阅、Spring 的 ApplicationEvent、前端的事件监听、WatchService 文件监控。
  • 优点:发布者和订阅者解耦,可动态增删订阅者。
  • 缺点:通知链过长影响性能;同步通知时一个观察者异常会影响其他观察者。

追问延伸

  • 观察者模式和消息队列的异同?
  • Spring 事件是同步还是异步?怎么改成异步?

Q4: 策略模式和 if-else 的关系? 「🟡 中级」

考察点:用模式重构坏味道的能力。

参考答案

  • 策略模式把一族算法封装成可互换的策略类,通过上下文持有策略接口来切换行为,消除大段 if-else / switch。
  • 配合工厂或 Map 注册表,按 key 取策略,新增算法只需新增类(符合开闭)。
  • 适用条件:分支逻辑复杂且稳定变化;只有两三个简单分支用 if-else 反而更清晰,不要过度设计。

追问延伸

  • 策略模式和状态模式的区别?(策略由外部选择,状态内部流转)
  • Java 里用枚举 + 函数式接口能怎么简化策略模式?

Q5: 代理模式和装饰器模式的区别? 「🟡 中级」

考察点:结构型模式的辨析能力。

参考答案

  • 二者结构相同(都持有一个同接口对象并转发调用),区别在意图:
    • 代理:控制对目标对象的访问(权限、懒加载、远程调用),客户端通常不感知;典型如 Spring AOP、MyBatis Mapper、RPC 客户端桩。
    • 装饰器:动态给对象增加功能,客户端主动选择装饰;典型如 Java IO 流 BufferedInputStream

追问延伸

  • Spring AOP 用的 JDK 动态代理还是 CGLIB?各什么条件?
  • 动态代理是怎么在运行时生成类的?

Q6: 说说模板方法模式 「🟡 中级」

考察点:框架设计常见套路。

参考答案

  • 父类定义算法骨架(流程步骤),把可变步骤留成抽象方法由子类实现。
  • 典型应用:AbstractQueuedSynchronizerJdbcTemplateHttpServletservice()、JUnit 的 setUp/tearDown
  • 体现了"好莱坞原则":别找我们,我们会找你。

追问延伸

  • 模板方法和策略模式都能消除重复流程,怎么选?
  • 钩子方法(hook)的作用是什么?