设计模式是 Java 面试的高频核心考点,面试官聚焦核心概念、应用场景、代码实现、优缺点、实际落地五大维度,以下是分类型的高频问题及标准答案,适配初/中/高级面试场景:
一、通用基础问题(必背)
1. 设计模式的核心原则(SOLID 原则)?各自的含义?
SOLID 是面向对象设计的基石,也是设计模式的底层逻辑:
| 原则 |
英文全称 |
核心含义 |
反例/场景 |
| 单一职责(S) |
Single Responsibility |
一个类只负责一个功能模块,避免“万能类” |
一个 UserService 既处理用户逻辑又处理订单逻辑 |
| 开闭原则(O) |
Open/Closed |
对扩展开放,对修改关闭(通过抽象/接口扩展) |
新增支付方式时,无需修改原有支付逻辑代码 |
| 里氏替换(L) |
Liskov Substitution |
子类可替换父类且不改变程序原有行为 |
正方形不能继承矩形(修改边长会破坏矩形逻辑) |
| 接口隔离(I) |
Interface Segregation |
拆分臃肿接口为多个专用接口,避免“接口污染” |
一个 PayInterface 拆分出 WechatPay/Alipay 接口 |
| 依赖倒置(D) |
Dependency Inversion |
依赖抽象而非具体实现(面向接口编程) |
依赖 Logger 接口而非 FileLogger 实现类 |
2. 设计模式分为哪几类?每类的核心目的?
| 类型 |
核心目的 |
代表模式 |
适用场景 |
| 创建型 |
封装对象的创建过程,解耦“创建”与“使用” |
单例、工厂方法、抽象工厂、建造者、原型 |
对象创建复杂(如多参数对象、不同类型对象) |
| 结构型 |
优化类/对象的组合方式,提升灵活性 |
代理、适配器、装饰器、桥接、组合、外观、享元 |
类结构扩展(如功能增强、接口适配) |
| 行为型 |
规范对象间的交互方式,提升协作效率 |
策略、模板方法、观察者、迭代器、责任链、命令、状态 |
对象通信/流程控制(如事件通知、流程复用) |
3. 设计模式的核心价值是什么?为什么要使用?
- 核心价值:代码复用、解耦、可扩展、易维护、符合面向对象设计原则;
- 具体作用:
- 解决通用问题(如单例解决资源独占,代理解决权限控制);
- 提升代码可读性(符合行业通用规范,便于团队协作);
- 降低维护成本(扩展功能时无需修改原有代码,符合开闭原则);
- 避免重复造轮子(复用成熟的设计思路,减少bug)。
二、创建型模式(高频考点)
1. 单例模式
(1)单例模式的核心特点?有哪些实现方式?
- 核心特点:保证一个类只有一个实例,且提供全局访问点;
- 常见实现方式(按推荐优先级排序):
| 实现方式 |
核心代码 |
线程安全 |
懒加载 |
适用场景 |
| 枚举单例 |
enum Singleton { INSTANCE; } |
是 |
否 |
简单场景(无懒加载需求,最优解) |
| 双重检查锁(DCL) |
private static volatile Singleton instance; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) instance = new Singleton(); } } return instance; } |
是 |
是 |
懒加载+高性能(生产首选) |
| 静态内部类 |
private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } |
是 |
是 |
懒加载(无锁,性能优) |
| 饿汉式 |
private static final Singleton INSTANCE = new Singleton(); |
是 |
否 |
实例创建成本低(如工具类) |
| 懒汉式(同步方法) |
public synchronized static Singleton getInstance() |
是 |
是 |
低并发(性能差,不推荐) |
(2)DCL 为什么要加 volatile?
- 原因:
instance = new Singleton() 不是原子操作,分为 3 步:① 分配内存;② 初始化对象;③ 引用指向内存;
- JVM 可能重排序(①→③→②),导致其他线程拿到“半初始化”的实例;
-
volatile 禁止指令重排序,保证实例初始化完成后才被其他线程可见。
(3)单例模式的优缺点?
- 优点:节省内存、避免资源重复创建(如数据库连接池);
- 缺点:
- 违背单一职责(既负责业务逻辑又负责实例管理);
- 不利于测试(单例无法被 mock,耦合度高);
- 多线程下若实现不当,可能出现多个实例。
(4)Spring 中的单例实现?
- Spring Bean 默认是单例(非线程安全),通过
DefaultSingletonBeanRegistry 维护一个 HashMap 存储单例实例;
- 与传统单例的区别:Spring 单例是“容器级”(一个 Bean 名称对应一个实例),而非“类级”(多个容器可创建多个实例)。
2. 工厂模式
(1)工厂模式分为哪几种?核心区别?
| 模式类型 |
核心实现 |
适用场景 |
| 简单工厂(非GOF) |
一个工厂类根据参数创建不同实例(如 ProductFactory.createProduct("A")) |
产品类型少、创建逻辑简单 |
| 工厂方法 |
抽象工厂类+多个具体工厂类(每个工厂创建一种产品) |
产品类型扩展频繁(新增产品只需加工厂) |
| 抽象工厂 |
一个工厂创建一组相关产品(如手机工厂创建手机+充电器) |
产品族扩展(如不同品牌的全套产品) |
(2)代码示例(工厂方法):
// 抽象产品
public interface Pay {
void pay();
}
// 具体产品
public class Alipay implements Pay {
@Override
public void pay() { System.out.println("支付宝支付"); }
}
public class WechatPay implements Pay {
@Override
public void pay() { System.out.println("微信支付"); }
}
// 抽象工厂
public interface PayFactory {
Pay createPay();
}
// 具体工厂
public class AlipayFactory implements PayFactory {
@Override
public Pay createPay() { return new Alipay(); }
}
public class WechatPayFactory implements PayFactory {
@Override
public Pay createPay() { return new WechatPay(); }
}
// 使用
public class Client {
public static void main(String[] args) {
PayFactory factory = new AlipayFactory();
Pay pay = factory.createPay();
pay.pay();
}
}
(3)工厂模式的核心价值?Spring 中的应用?
- 核心价值:解耦“产品创建”与“产品使用”,符合依赖倒置原则(依赖抽象而非具体);
- Spring 应用:
-
BeanFactory 是工厂模式的核心(ApplicationContext 继承自 BeanFactory);
-
FactoryBean 用于创建复杂 Bean(如 MyBatis 的 SqlSessionFactoryBean)。
3. 建造者模式
(1)建造者模式的核心作用?与工厂模式的区别?
- 核心作用:构建复杂对象(多参数、可选参数),分步构建、统一组装(如
User 对象有姓名、年龄、地址等可选字段);
- 与工厂模式的区别:
- 工厂模式:关注“创建”,直接返回产品实例;
- 建造者模式:关注“构建过程”,分步设置属性,最后组装返回。
(2)代码示例(链式建造者):
public class User {
private String name;
private Integer age;
private String address;
// 私有构造器
private User(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.address = builder.address;
}
// 静态内部建造者
public static class Builder {
private String name;
private Integer age;
private String address;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(Integer age) {
this.age = age;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public User build() {
return new User(this);
}
}
// 使用
public static void main(String[] args) {
User user = new User.Builder()
.name("张三")
.age(20)
.address("北京")
.build();
}
}
(3)建造者模式的应用场景?
- 复杂对象构建(如
StringBuilder、MyBatis 的 SqlSessionFactoryBuilder);
- 多参数对象(尤其是可选参数多),避免构造器参数过多( Telescoping Constructor 反模式)。
三、结构型模式(高频考点)
1. 代理模式
(1)代理模式分为哪几种?核心区别?
| 类型 |
实现方式 |
适用场景 |
示例 |
| 静态代理 |
手动编写代理类,实现与目标类相同接口 |
代理逻辑固定(如简单的权限控制) |
自定义 UserServiceProxy 代理 UserService
|
| 动态代理 |
JDK 动态代理(基于接口) |
代理多个类,接口统一 |
Spring AOP(JDK 代理) |
|
CGLIB 动态代理(基于继承) |
目标类无接口 |
Spring AOP(CGLIB 代理) |
(2)JDK 动态代理 vs CGLIB 动态代理?
| 维度 |
JDK 动态代理 |
CGLIB 动态代理 |
| 底层实现 |
反射 + 接口实现 |
ASM 字节码生成 + 继承目标类 |
| 要求 |
目标类必须实现接口 |
目标类不能是 final(无法继承) |
| 性能 |
JDK 8+ 性能优于 CGLIB |
生成子类耗时,运行时性能略高 |
| 方法增强 |
只能代理接口方法 |
可代理所有方法(包括非接口方法) |
(3)代码示例(JDK 动态代理):
// 目标接口
public interface UserService {
void addUser();
}
// 目标类
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
}
// 代理处理器
public class ProxyHandler implements InvocationHandler {
private Object target;
public ProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强:权限校验
System.out.println("权限校验");
// 执行目标方法
Object result = method.invoke(target, args);
// 后置增强:日志记录
System.out.println("日志记录");
return result;
}
}
// 使用
public class Client {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new ProxyHandler(target)
);
proxy.addUser();
}
}
(4)代理模式的核心应用?
- Spring AOP(核心是动态代理,实现横切逻辑如事务、日志、权限);
- MyBatis 的 Mapper 代理(动态生成 Mapper 实现类,避免手动编写);
- RPC 框架(如 Dubbo 的服务代理,实现远程调用)。
2. 装饰器模式
(1)装饰器模式的核心作用?与继承的区别?
- 核心作用:动态给对象添加功能,不改变原有类结构(符合开闭原则);
- 与继承的区别:
- 继承:静态扩展(编译期确定,子类膨胀);
- 装饰器:动态扩展(运行期组合,灵活添加/移除功能)。
(2)代码示例(IO 流装饰器):
// 抽象组件
public interface Stream {
void write(String data);
}
// 具体组件
public class FileStream implements Stream {
@Override
public void write(String data) {
System.out.println("写入文件:" + data);
}
}
// 抽象装饰器
public abstract class StreamDecorator implements Stream {
protected Stream stream;
public StreamDecorator(Stream stream) {
this.stream = stream;
}
}
// 具体装饰器:加密装饰
public class EncryptDecorator extends StreamDecorator {
public EncryptDecorator(Stream stream) {
super(stream);
}
@Override
public void write(String data) {
// 加密处理
String encryptData = data + "_encrypt";
// 调用原有功能
stream.write(encryptData);
}
}
// 使用
public class Client {
public static void main(String[] args) {
Stream stream = new EncryptDecorator(new FileStream());
stream.write("hello"); // 输出:写入文件:hello_encrypt
}
}
(3)装饰器模式的应用场景?
- JDK IO 流(如
BufferedReader 装饰 Reader,DataOutputStream 装饰 OutputStream);
- Spring 的
TransactionAwareCacheDecorator(装饰缓存,增加事务支持)。
3. 适配器模式
(1)适配器模式的核心作用?分为哪几种?
- 核心作用:将一个类的接口转换成客户端期望的另一个接口,解决接口不兼容问题;
- 分类:
- 类适配器(继承):目标类 + 适配者类(Java 单继承,少用);
- 对象适配器(组合):持有适配者实例(推荐,更灵活);
- 接口适配器(默认适配器):空实现接口方法,子类按需重写(如
MouseAdapter)。
(2)代码示例(对象适配器):
// 客户端期望的接口
public interface Payment {
void pay();
}
// 适配者(第三方接口,接口不兼容)
public class AlipaySDK {
public void doAlipay() {
System.out.println("支付宝支付SDK");
}
}
// 适配器
public class AlipayAdapter implements Payment {
private AlipaySDK alipaySDK;
public AlipayAdapter(AlipaySDK alipaySDK) {
this.alipaySDK = alipaySDK;
}
@Override
public void pay() {
// 适配第三方接口
alipaySDK.doAlipay();
}
}
// 使用
public class Client {
public static void main(String[] args) {
Payment payment = new AlipayAdapter(new AlipaySDK());
payment.pay();
}
}
(3)适配器模式 vs 装饰器模式?
| 维度 |
适配器模式 |
装饰器模式 |
| 核心目的 |
解决接口不兼容 |
扩展对象功能 |
| 结构 |
持有适配者实例(组合) |
持有被装饰者实例(组合) |
| 接口 |
改变原有接口 |
保持原有接口 |
| 场景 |
集成第三方组件(接口不一致) |
动态添加功能(如 IO 流缓冲) |
4. 外观模式(门面模式)
(1)核心作用?应用场景?
- 核心作用:为复杂子系统提供统一入口,简化客户端调用(如
OrderService 整合库存、支付、物流子系统);
- 应用场景:
- 简化复杂 API 调用(如 JDBC 封装为
JdbcTemplate);
- 微服务网关(整合多个微服务接口,提供统一入口)。
(2)代码示例:
// 子系统1:库存服务
public class InventoryService {
public void reduceStock() { System.out.println("扣减库存"); }
}
// 子系统2:支付服务
public class PayService {
public void pay() { System.out.println("支付扣款"); }
}
// 子系统3:物流服务
public class LogisticsService {
public void createOrder() { System.out.println("创建物流订单"); }
}
// 外观类
public class OrderFacade {
private InventoryService inventoryService = new InventoryService();
private PayService payService = new PayService();
private LogisticsService logisticsService = new LogisticsService();
// 统一入口
public void createOrder() {
inventoryService.reduceStock();
payService.pay();
logisticsService.createOrder();
}
}
// 使用
public class Client {
public static void main(String[] args) {
OrderFacade facade = new OrderFacade();
facade.createOrder(); // 一行代码调用多个子系统
}
}
四、行为型模式(高频考点)
1. 策略模式
(1)核心作用?解决什么问题?
- 核心作用:定义一组算法,封装每个算法,使算法可互相替换(客户端无感知);
- 解决问题:避免大量
if-else/switch 分支(如不同支付方式、不同排序算法)。
(2)代码示例:
// 策略接口
public interface SortStrategy {
void sort(int[] arr);
}
// 具体策略:冒泡排序
public class BubbleSort implements SortStrategy {
@Override
public void sort(int[] arr) { System.out.println("冒泡排序"); }
}
// 具体策略:快速排序
public class QuickSort implements SortStrategy {
@Override
public void sort(int[] arr) { System.out.println("快速排序"); }
}
// 上下文
public class Sorter {
private SortStrategy strategy;
public Sorter(SortStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(SortStrategy strategy) {
this.strategy = strategy;
}
public void sortArray(int[] arr) {
strategy.sort(arr);
}
}
// 使用
public class Client {
public static void main(String[] args) {
Sorter sorter = new Sorter(new BubbleSort());
sorter.sortArray(new int[]{1,3,2});
// 切换策略
sorter.setStrategy(new QuickSort());
sorter.sortArray(new int[]{1,3,2});
}
}
(3)策略模式的应用场景?
- Spring 的
Resource 接口(不同资源加载策略:文件、类路径、URL);
- MyBatis 的
Executor 接口(不同执行器策略:SimpleExecutor、BatchExecutor);
- 电商的优惠策略(满减、折扣、优惠券)。
2. 模板方法模式
(1)核心作用?核心结构?
- 核心作用:定义算法骨架,将可变步骤延迟到子类实现(复用固定逻辑,扩展可变逻辑);
- 核心结构:
- 抽象父类:定义模板方法(固定算法流程)+ 抽象方法(可变步骤);
- 具体子类:实现抽象方法,定制可变步骤。
(2)代码示例:
// 抽象父类
public abstract class AbstractTemplate {
// 模板方法(final 防止子类重写)
public final void process() {
// 固定步骤1
step1();
// 可变步骤(子类实现)
step2();
// 固定步骤3
step3();
}
private void step1() { System.out.println("固定步骤1:初始化"); }
protected abstract void step2(); // 可变步骤
private void step3() { System.out.println("固定步骤3:完成"); }
}
// 具体子类1
public class ConcreteTemplate1 extends AbstractTemplate {
@Override
protected void step2() { System.out.println("子类1:执行业务逻辑A"); }
}
// 具体子类2
public class ConcreteTemplate2 extends AbstractTemplate {
@Override
protected void step2() { System.out.println("子类2:执行业务逻辑B"); }
}
// 使用
public class Client {
public static void main(String[] args) {
AbstractTemplate template = new ConcreteTemplate1();
template.process();
}
}
(3)模板方法模式的应用?
- Spring 的
JdbcTemplate(固定 JDBC 流程,子类实现 RowMapper 处理结果);
- Servlet 的
doGet/doPost(service 方法是模板方法,子类实现具体逻辑);
- MyBatis 的
BaseExecutor(固定执行流程,子类实现具体执行逻辑)。
3. 观察者模式
(1)核心作用?核心角色?
- 核心作用:定义对象间的一对多依赖,当一个对象状态变化时,所有依赖者自动收到通知;
- 核心角色:
- 主题(Subject):维护观察者列表,提供注册/移除/通知方法;
- 观察者(Observer):定义更新方法,接收主题通知。
(2)代码示例(JDK 自带 Observer/Observable):
// 主题(被观察者)
public class WeatherData extends Observable {
private float temperature;
public void setTemperature(float temperature) {
this.temperature = temperature;
setChanged(); // 标记状态变化
notifyObservers(temperature); // 通知观察者
}
}
// 观察者1:控制台显示
public class ConsoleDisplay implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("当前温度:" + arg);
}
}
// 使用
public class Client {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
weatherData.addObserver(new ConsoleDisplay());
weatherData.setTemperature(25.0f); // 输出:当前温度:25.0
}
}
(3)观察者模式的应用?
- Spring 的事件监听机制(
ApplicationEvent/ApplicationListener);
- Guava 的
EventBus(简化观察者模式实现);
- 消息队列(如 RocketMQ 的生产者/消费者模型)。
4. 责任链模式
(1)核心作用?核心结构?
- 核心作用:将请求的处理者连成一条链,请求沿链传递,直到被处理(解耦请求发送者和处理者);
- 核心结构:
- 抽象处理器:定义处理方法 + 设置下一个处理器;
- 具体处理器:实现处理逻辑,若无法处理则传递给下一个。
(2)代码示例:
// 抽象处理器
public abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handleRequest(String request);
}
// 具体处理器1:权限校验
public class AuthHandler extends Handler {
@Override
public void handleRequest(String request) {
if ("login".equals(request)) {
System.out.println("权限校验通过");
if (nextHandler != null) {
nextHandler.handleRequest(request);
}
} else {
System.out.println("权限校验失败");
}
}
}
// 具体处理器2:日志记录
public class LogHandler extends Handler {
@Override
public void handleRequest(String request) {
System.out.println("日志记录:" + request);
}
}
// 使用
public class Client {
public static void main(String[] args) {
Handler authHandler = new AuthHandler();
Handler logHandler = new LogHandler();
authHandler.setNextHandler(logHandler);
authHandler.handleRequest("login"); // 输出:权限校验通过 → 日志记录:login
}
}
(3)责任链模式的应用?
- Spring MVC 的
HandlerInterceptor(拦截器链);
- Servlet 的
Filter(过滤器链);
- Dubbo 的
Filter(过滤器链);
- MyBatis 的
Interceptor(插件链)。
五、面试高频扩展问题
1. 设计模式在 Spring 中的应用有哪些?
| 模式 |
Spring 应用场景 |
| 单例模式 |
Bean 默认单例(DefaultSingletonBeanRegistry) |
| 工厂模式 |
BeanFactory/FactoryBean 创建 Bean |
| 代理模式 |
AOP 动态代理(JDK/CGLIB) |
| 装饰器模式 |
TransactionAwareCacheDecorator 装饰缓存 |
| 模板方法 |
JdbcTemplate/RestTemplate 固定流程 |
| 观察者模式 |
事件监听(ApplicationEvent/ApplicationListener) |
| 责任链模式 |
HandlerInterceptor 拦截器链 |
| 策略模式 |
Resource 资源加载策略、TransactionManager 事务管理器 |
2. 如何选择设计模式?核心思路?
- 先明确问题:是“创建对象”“组合类/对象”还是“协调对象交互”;
- 遵循 SOLID 原则:优先保证代码可扩展、可维护;
- 避免过度设计:简单场景用简单方案(如简单工厂优于抽象工厂);
- 结合业务场景:
- 复杂对象创建 → 建造者模式;
- 功能动态扩展 → 装饰器模式;
- 接口不兼容 → 适配器模式;
- 分支逻辑多 → 策略模式。
3. 设计模式的常见反模式?
- 滥用单例:所有类都设计为单例,导致耦合高、测试难;
- 过度继承:用继承代替组合/装饰器,导致类爆炸;
- 万能工厂:一个工厂类创建所有产品,违反单一职责;
- 硬编码依赖:直接 new 实例,而非依赖注入(违反依赖倒置)。
4. 组合模式 vs 装饰器模式?
- 组合模式:处理“部分-整体”结构(如树形结构:部门→员工),关注对象的层级组合;
- 装饰器模式:处理“功能扩展”,关注对象的功能增强,无层级关系。
六、面试速记口诀
- 设计原则记 SOLID,开闭原则是核心;
- 创建型:单例(DCL)、工厂(解耦创建)、建造者(复杂对象);
- 结构型:代理(增强)、装饰(扩展)、适配器(兼容)、外观(简化);
- 行为型:策略(去分支)、模板(固定流程)、观察者(通知)、责任链(传递);
- Spring 核心用代理(AOP)、工厂(Bean)、模板(Jdbc)、观察者(事件)。