设计模式精讲面试
深入理解23种设计模式,掌握架构设计精髓,从容应对大厂技术面试。单例模式、工厂模式、观察者模式... 一站式掌握核心考点。
核心设计模式精讲
创建型模式:对象的诞生艺术
创建型模式关注对象的创建过程,旨在将对象的创建与使用分离,降低系统耦合度。
① 单例模式 (Singleton)
核心定义:确保一个类只有一个实例,并提供一个全局访问点。
面试考点:懒汉式 vs 饿汉式、双重检查锁(DCL)、枚举单例、线程安全。
应用场景:Spring Bean默认单例、数据库连接池、配置中心。
public class Singleton {
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;
}
}
② 工厂模式 (Factory)
核心定义:定义创建对象的接口,让子类决定实例化哪一个类。
面试考点:简单工厂、工厂方法、抽象工厂的区别;开闭原则的体现。
应用场景:JDBC Driver加载、MyBatis Mapper代理创建。
③ 建造者模式 (Builder)
核心定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
面试考点:链式调用、参数过多时的替代方案、Java StringBuilder源码。
结构型模式:类与对象的组合
结构型模式关注类和对象的组合,通过继承或组合来放大现有功能。
④ 适配器模式 (Adapter)
核心定义:将一个类的接口转换成客户希望的另外一个接口。
面试考点:类适配器 vs 对象适配器、Spring MVC HandlerAdapter。
⑤ 代理模式 (Proxy)
核心定义:为其他对象提供一种代理以控制对这个对象的访问。
面试考点:JDK动态代理 vs CGLIB、AOP底层原理、远程代理、虚拟代理。
⑥ 装饰器模式 (Decorator)
核心定义:动态地给一个对象添加一些额外的职责。
面试考点:Java IO流设计、Spring Security过滤器链。
行为型模式:对象间的通信
行为型模式关注对象之间的通信,封装系统中对象之间的相互作用。
⑦ 观察者模式 (Observer)
核心定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
面试考点:发布订阅模式区别、Spring Event机制、MQ解耦。
⑧ 策略模式 (Strategy)
核心定义:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。
面试考点:消除多重if-else、Spring Validation、支付渠道选择。
⑨ 模板方法模式 (Template)
核心定义:定义一个操作中的算法骨架,而将一些步骤延迟到子类中。
面试考点:钩子方法、Spring JdbcTemplate、Servlet生命周期。
高频面试真题解析
以下是面试官在考察设计模式时最常问到的问题,以及深度解答。
Spring框架是Java设计模式的集大成者。例如:
- ① 工厂模式:BeanFactory用于创建和管理Bean实例。
- ② 单例模式:Spring容器中Bean默认是单例的,通过singletonObjects Map实现。
- ③ 代理模式:AOP底层通过JDK动态代理或CGLIB实现,增强业务逻辑。
- ④ 模板方法模式:JdbcTemplate、RestTemplate等简化了资源管理和异常处理。
- ⑤ 观察者模式:ApplicationEventPublisher和ApplicationListener实现事件驱动。
理解这些模式能帮助你更好地阅读Spring源码,并在实际开发中灵活运用。
保证单例线程安全主要有以下几种方式:
- ① 饿汉式:类加载时即创建实例,天然线程安全,但可能浪费资源。
- ② 懒汉式+ synchronized:简单但性能差,每次调用都加锁。
- ③ 双重检查锁(DCL):先判断instance是否为null,不为null直接返回;为null再 synchronized,再次判断。需要 volatile 关键字防止指令重排。
- ④ 静态内部类:利用类加载机制保证线程安全,推荐方式。
- ⑤ 枚举:由JVM保证线程安全,防止反射和序列化破坏单例,最推荐方式。
使用策略模式结合工厂模式或Map映射可以优雅地消除if-else:
// 定义策略接口
public interface PaymentStrategy {
void pay(double amount);
}
// 具体策略
public class AlipayStrategy implements PaymentStrategy {
public void pay(double amount) { System.out.println("支付宝支付: " + amount); }
}
// 上下文/工厂
public class PaymentContext {
private Map strategies = new HashMap<>();
public PaymentContext() {
strategies.put("alipay", new AlipayStrategy());
strategies.put("wechat", new WechatPayStrategy());
}
public void execute(String type, double amount) {
strategies.get(type).pay(amount);
}
}
这样新增支付方式只需增加一个类并注册到Map中,符合开闭原则。
源码中的设计模式
Java IO流
装饰器模式的典型应用。例如 BufferedInputStream 装饰 FileInputStream,在不修改原有类的情况下增加缓冲功能。
Spring AOP
代理模式的应用。Spring通过动态代理为目标Bean创建代理对象,从而在方法执行前后织入横切逻辑(如事务管理、日志记录)。
MyBatis Mapper
工厂模式和代理模式。SqlSessionConfiguration创建MapperProxyFactory,MapperProxy实现InvocationHandler,动态生成Mapper接口实现。
Servlet Filter
责任链模式的应用。多个Filter按顺序执行,形成链式调用,每个Filter可以决定是否继续执行后续Filter或提前返回。
常见问题解答 (FAQ)
建议按照创建型→结构型→行为型的顺序学习。首先掌握单例模式、工厂模式、建造者模式,这些在实际开发中最常用。然后是代理模式、装饰器模式。最后是观察者、策略等行为型模式。
设计模式绝非只是为了面试。它们是前人总结的最佳实践,能帮助你编写出高内聚、低耦合、易扩展、易维护的代码。例如,使用策略模式可以避免大量的if-else,使用工厂模式可以简化对象创建逻辑。在实际工作中,理解设计模式能让你更快速地阅读和理解开源框架源码。
关键看需求:
- ① 需要创建对象且解耦?→ 工厂模式、建造者模式。
- ② 需要保证唯一实例?→ 单例模式。
- ③ 需要扩展功能而不修改原类?→ 装饰器模式。
- ④ 需要动态替换算法?→ 策略模式。
- ⑤ 需要一对多通知?→ 观察者模式。
多读开源框架源码,观察它们如何使用设计模式解决实际问题,是提升的关键。