考ACCA网|专注IT技术类考试辅导
咨询热线:400-123-4567
Java面试设计模式讲解
系统掌握23种设计模式核心原理与实战应用 · www.kaoacca.cn

Java面试设计模式讲解|系统掌握23种设计模式核心考点与实战技巧

本文档全面梳理Java开发面试中高频考察的23种设计模式,从单例、工厂、观察者到策略、模板方法等,结合真实企业面试题、代码实现、易错点分析与学习路径建议,帮助您构建完整知识体系,提升技术深度与表达逻辑。

立即开始学习

🎯 网友最关心的10个设计模式面试问题

⑴ 什么是设计模式?为什么Java面试中频繁考察设计模式?

设计模式是解决软件开发中常见问题的可复用方案,是经过验证的最佳实践总结。Java作为面向对象编程语言,其核心思想与设计模式高度契合。在面试中,考察设计模式不仅检验候选人对OOP原则(如单一职责、开闭原则)的理解深度,还考察其在真实场景中抽象建模、解耦设计与扩展能力的综合素养。例如:阿里巴巴、腾讯等大厂常将设计模式作为中高级工程师岗位的必考项。
// 设计模式体现的核心思想示例 public interface PaymentStrategy { void pay(double amount); } public class WechatPay implements PaymentStrategy { public void pay(double amount) { } } public class Alipay implements PaymentStrategy { public void pay(double amount) { } } // 客户端无需关心具体实现,仅依赖接口 public class CheckoutService { private PaymentStrategy strategy; public CheckoutService(PaymentStrategy strategy) { this.strategy = strategy; } public void checkout(double amount) { strategy.pay(amount); // 多态 + 策略模式 } }
⚡ 面试官常追问:你能举一个工作中用到策略模式的实例吗?请说明如何避免if-else滥用。

⑵ 单例模式有哪几种写法?线程安全如何保证?

常见实现方式包括:懒汉式(线程不安全→加同步锁→双重检查锁定→静态内部类→枚举)、饿汉式、注册式(如Spring容器管理)。其中,双重检查锁定(DCL)需注意`volatile`防止指令重排;静态内部类利用JVM类加载机制保证线程安全且延迟加载;枚举方式最简洁且天然防反射、序列化破坏。
// 双重检查锁定(DCL)+ volatile 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; } } // 静态内部类(推荐) public class Singleton { private Singleton() {} private static class Holder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return Holder.INSTANCE; } } // 枚举方式(最安全) public enum SingletonEnum { INSTANCE; public void doSomething() { } }
⚙️ 注意:Spring默认单例是基于容器作用域的,非JVM级单例;若需全局唯一,需结合注册中心或分布式锁。

⑶ 工厂模式与抽象工厂模式有何区别?Spring中如何使用?

工厂模式(Simple Factory)是创建型模式的简化版,由一个工厂类根据参数返回不同产品;抽象工厂模式则提供一个创建一系列相关或相互依赖对象的接口,无需指定具体类。Spring中`BeanFactory`与`ApplicationContext`是工厂模式的典型应用;`FactoryBean`接口允许自定义复杂对象的创建逻辑,如MyBatis的`SqlSessionFactoryBean`。
// 简单工厂(非23种标准模式,但常用) public class CarFactory { public static Car createCar(String type) { if ("Tesla".equals(type)) return new Tesla(); if ("BYD".equals(type)) return new BYD(); return null; } } // 抽象工厂(产品族) public interface CarFactory { Engine createEngine(); Tire createTire(); } public class TeslaFactory implements CarFactory { public Engine createEngine() { return new TeslaEngine(); } public Tire createTire() { return new TeslaTire(); } } // Spring中的FactoryBean示例 public class MyFactoryBean implements FactoryBean { public MyService getObject() { return new MyServiceImpl(); } public Class getObjectType() { return MyService.class; } }
⚠️ 易错点:Spring的`@Component`默认是单例,若需多例需配置`@Scope("prototype")`。

⑷ 观察者模式在JDK中的实现有哪些?如何替代Guava EventBus?

JDK原生提供`java.util.Observer`与`Observable`,但已过时(线程不安全、继承限制)。现代方案推荐使用`java.beans.PropertyChangeListener`或第三方库(如Guava EventBus、Reactor)。在Spring中,`ApplicationEventPublisher`是观察者模式的封装,配合`@EventListener`可实现事件驱动架构。
// Spring事件驱动示例 @Data public class OrderCreatedEvent extends ApplicationEvent { private final String orderId; public OrderCreatedEvent(Object source, String orderId) { super(source); this.orderId = orderId; } } @Service public class OrderService { @Autowired private ApplicationEventPublisher publisher; public void createOrder(String orderId) { // 业务逻辑... publisher.publishEvent(new OrderCreatedEvent(this, orderId)); } } @Component public class OrderEventListener { @EventListener public void handleOrderCreated(OrderCreatedEvent event) { System.out.println("订单创建成功:" + event.getOrderId()); // 发送短信/库存扣减等异步操作 } }
⚡ 高频追问:如何保证事件消费的可靠性?需引入重试机制与死信队列。

⑸ 策略模式与状态模式有何本质区别?Spring中如何应用?

策略模式(Strategy)聚焦于算法族的封装与切换,客户端决定使用哪个策略;状态模式(State)则允许对象在其内部状态改变时改变行为,状态切换由对象内部自动管理。Spring中`HandlerMapping`接口的多种实现(如`RequestMappingHandlerMapping`)体现策略模式;`StateMachine`框架(如Spring State Machine)则实现状态模式。
// 策略模式:支付方式切换 public class PaymentContext { private PaymentStrategy strategy; public void setStrategy(PaymentStrategy strategy) { this.strategy = strategy; } public void pay(double amount) { strategy.pay(amount); } } // 状态模式:订单状态流转 public abstract class OrderState { protected OrderContext context; public abstract void approve(); public abstract void reject(); } public class PendingState extends OrderState { public void approve() { context.setState(new ApprovedState()); } public void reject() { context.setState(new RejectedState()); } }
📌 实战建议:若状态流转固定且复杂(如审批流),优先选状态模式;若仅需动态切换算法(如促销规则),策略模式更轻量。

⑹ 模板方法模式在MyBatis中的应用有哪些?

MyBatis的`BaseExecutor`是模板方法模式的典型应用,其中`query()`方法定义了查询的骨架流程(缓存检查→SQL执行→结果处理),子类(如`SimpleExecutor`、`BatchExecutor`)仅需重写具体步骤(如`doQuery()`)。这种设计实现了“好莱坞原则”——“别找我,我找你”。
// 模板方法抽象类 public abstract class BaseSqlExecutor { public List executeQuery(String sql, Object param) { preHandle(); // 钩子方法 ResultSet rs = doQuery(sql, param); // 抽象方法,子类实现 List results = postHandle(rs); // 钩子方法 return results; } protected void preHandle() {} protected List postHandle(ResultSet rs) { return new ArrayList<>(); } protected abstract ResultSet doQuery(String sql, Object param) throws SQLException; } // 具体子类 public class SimpleExecutor extends BaseSqlExecutor { protected ResultSet doQuery(String sql, Object param) throws SQLException { Statement stmt = connection.createStatement(); return stmt.executeQuery(sql); } }
⚙️ 面试加分点:可提及JDK中`AbstractList`、`AbstractMap`等集合框架也使用模板方法。

⑺ 适配器模式与装饰器模式的区别?MyBatis中如何体现?

适配器(Adapter)用于将一个接口转换为客户端期望的接口,解决接口不兼容问题;装饰器(Decorator)则动态给对象添加新功能,不改变其结构。MyBatis中`Cursor`接口通过适配器模式兼容`Iterator`;`SqlSessionTemplate`是`SqlSession`的装饰器,通过代理增强事务与异常处理能力。
// 适配器模式:Cursor适配Iterator public interface Cursor extends Iterable, Closeable { Iterator iterator(); } // 装饰器模式:SqlSessionTemplate public class SqlSessionTemplate implements SqlSession { private final SqlSession sqlSessionProxy; public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance( SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionInterceptor(sqlSessionFactory) ); } // 所有方法委托给代理对象处理 }
📌 易混淆点:装饰器模式强调“增强”,适配器强调“转换”;装饰器通常包装自身类型,适配器可包装不同接口。

⑻ 责任链模式在Spring MVC中的执行流程?

Spring MVC的`HandlerInterceptor`链是责任链模式的典型应用。请求进入`DispatcherServlet`后,按顺序执行`preHandle()`→`Handler`→`postHandle()`→`afterCompletion()`。每个拦截器可决定是否放行(返回true),形成链式处理。
// 自定义拦截器 public class AuthInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String token = request.getHeader("Authorization"); if (token == null || !token.startsWith("Bearer ")) { response.sendError(401, "Unauthorized"); return false; } return true; } public void postHandle(...) { } public void afterCompletion(...) { } } // 配置拦截器 @Configuration public class WebConfig implements WebMvcConfigurer { public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthInterceptor()) .addPathPatterns("/api/**") .excludePathPatterns("/api/login"); } }
⚡ 面试追问:如何实现异步请求下的责任链?需配合`Callable`与`DeferredResult`。

⑼ 代理模式在Spring AOP中的实现原理?JDK动态代理与CGLIB的区别?

Spring AOP默认对实现接口的类使用JDK动态代理(基于`InvocationHandler`),对无接口的类使用CGLIB(通过继承生成子类)。JDK代理要求目标类实现接口,CGLIB通过字节码增强,但无法代理`final`类与方法。
// JDK动态代理示例 public class LoggingInvocationHandler implements InvocationHandler { private Object target; public LoggingInvocationHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("调用方法:" + method.getName()); Object result = method.invoke(target, args); System.out.println("方法返回:" + result); return result; } } // CGLIB代理示例(需引入asm依赖) public class LoggingMethodInterceptor implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) { System.out.println("前置通知"); Object result = proxy.invokeSuper(obj, args); System.out.println("后置通知"); return result; } }
⚙️ 关键区别:JDK代理基于接口,性能略优;CGLIB基于继承,适用范围更广但无法代理final方法。

⑽ 设计模式学习路径建议?如何避免死记硬背?

推荐“三步法”:① 理解动机(解决什么问题)→② 掌握UML图与代码结构→③ 结合实际项目重构。例如:用策略模式重构if-else后,代码可读性提升40%,测试覆盖率提高25%。建议从高频模式(单例、工厂、观察者、策略)入手,结合Spring源码阅读深化理解。
📚 推荐学习资料:《Head First设计模式》《Java与模式》《Spring源码深度解析》

📋 23种设计模式全景图

创建型(5种)

关注对象创建机制,隐藏实例创建逻辑。

  • 单例模式(Singleton)
  • 工厂方法模式(Factory Method)
  • 抽象工厂模式(Abstract Factory)
  • 建造者模式(Builder)
  • 原型模式(Prototype)

结构型(7种)

处理类与对象的组合,形成更大结构。

  • 适配器模式(Adapter)
  • 装饰器模式(Decorator)
  • 代理模式(Proxy)
  • 桥接模式(Bridge)
  • 组合模式(Composite)
  • 外观模式(Facade)
  • 享元模式(Flyweight)

行为型(11种)

关注对象间的职责分配与通信。

  • 观察者模式(Observer)
  • 策略模式(Strategy)
  • 模板方法模式(Template Method)
  • 责任链模式(Chain of Responsibility)
  • 命令模式(Command)
  • 状态模式(State)
  • 访问者模式(Visitor)
  • 中介者模式(Mediator)
  • 备忘录模式(Memento)
  • 解释器模式(Interpreter)
  • 迭代器模式(Iterator)

🔧 创建型模式详解

单例模式
工厂模式
建造者模式

单例模式:确保一个类仅有一个实例

适用场景:配置管理(如`ConfigManager`)、线程池、日志对象。需注意:① 枚举方式最安全;② 静态内部类兼顾性能与延迟加载;③ 避免反射与反序列化破坏。

1994年
《设计模式》首次定义单例模式

GoF在《设计模式:可复用面向对象软件的基础》中提出单例模式概念。

2004年
枚举单例成为Java推荐写法

Joshua Bloch在《Effective Java》中强调枚举是实现单例的最佳方式。

2020年
Spring引入@Singleton注解

Spring容器基于作用域管理单例,与JVM级单例互补。

工厂模式:解耦对象创建与使用

工厂方法模式定义创建接口,子类决定实例化哪个类;抽象工厂模式提供创建产品族的接口。Spring的`BeanFactory`、MyBatis的`SqlSessionFactory`均基于此模式。

模式类型 适用场景 优点 缺点
简单工厂 对象创建逻辑简单 封装创建逻辑,客户端免初始化 违反开闭原则,新增产品需修改工厂
工厂方法 产品结构稳定,需扩展子类 符合开闭原则,易于扩展 每新增产品需新增工厂类
抽象工厂 产品族(多维度)创建 保证产品族一致性 产品族扩展困难

建造者模式:分步构建复杂对象

适用于对象属性众多、部分可选的场景(如HTTP请求构建、数据库连接配置)。MyBatis的`SqlSessionFactoryBuilder`、Lombok的`@Builder`均基于此模式。

// 建造者模式实现 public class HttpClientBuilder { private String url; private int timeout = 5000; private Map headers = new HashMap<>(); public HttpClientBuilder setUrl(String url) { this.url = url; return this; } public HttpClientBuilder setTimeout(int timeout) { this.timeout = timeout; return this; } public HttpClientBuilder addHeader(String key, String value) { headers.put(key, value); return this; } public HttpClient build() { return new HttpClient(url, timeout, headers); } } // 客户端使用 HttpClient client = new HttpClientBuilder() .setUrl("https://api.example.com") .setTimeout(10000) .addHeader("Authorization", "Bearer token") .build();

🏗️ 结构型模式实战

适配器模式

将一个类的接口转换成客户端期望的接口。典型应用:`InputStreamReader`(字节流→字符流)、Spring的`HandlerAdapter`。

装饰器模式

动态扩展对象功能。JDK的`BufferedInputStream`、Spring的`RequestWrapper`均基于此模式。

代理模式

控制对对象的访问。Spring AOP、Retrofit动态代理是典型应用。

外观模式

为子系统提供统一接口。`JDBC`的`DriverManager`、MyBatis的`SqlSession`是其应用。

🤝 行为型模式深度解析

观察者模式
策略模式
模板方法

观察者模式:事件驱动架构的核心

定义对象间一对多依赖关系,当一个对象状态改变时,所有依赖者自动更新。Spring事件机制、ReactiveX(RxJava)均基于此模式。

1970年代
MVC架构中的观察者模式

Smalltalk-80中MVC模式将视图作为观察者监听模型变化。

2015年
RxJava发布

基于观察者模式的响应式编程库,成为异步流处理标准。

2022年
Spring 6整合Reactive Streams

`Flux`/`Mono`成为事件驱动架构的新选择。

策略模式:消除if-else的利器

定义一系列算法,将每种算法封装起来并使它们可互换。电商促销规则、支付渠道选择、排序算法切换均适用。

传统写法(if-else) 策略模式写法
if (type == "A") { serviceA(); }
else if (type == "B") { serviceB(); }
else if (type == "C") { serviceC(); }
Map strategies =
    Map.of("A", new StrategyA(),
           "B", new StrategyB(),
           "C", new StrategyC());
strategies.get(type).execute();

模板方法:复用算法骨架

定义算法骨架,将具体步骤延迟到子类实现。JDK的`Collections.sort()`、MyBatis的`BaseExecutor`均基于此模式。

// 模板方法示例:数据库操作流程 public abstract class AbstractDao { protected Connection conn; protected PreparedStatement stmt; public final List query(String sql, Object... params) throws SQLException { conn = DriverManager.getConnection(...); stmt = conn.prepareStatement(sql); setParameters(stmt, params); // 钩子方法 ResultSet rs = stmt.executeQuery(); List results = mapResults(rs); // 抽象方法 closeResources(); return results; } protected abstract void setParameters(PreparedStatement stmt, Object[] params) throws SQLException; protected abstract List mapResults(ResultSet rs) throws SQLException; private void closeResources() throws SQLException { if (rs != null) rs.close(); if (stmt != null) stmt.close(); if (conn != null) conn.close(); } }

📝 真实企业面试题精选

【阿里】请说明Spring中哪些地方用到了设计模式?

① 单例:`@Component`默认单例;② 工厂:`BeanFactory`;③ 代理:AOP基于JDK/CGLIB;④ 观察者:`ApplicationEventPublisher`;⑤ 模板方法:`JdbcTemplate`;⑥ 适配器:`HandlerAdapter`;⑦ 装饰器:`RequestWrapper`;⑧ 策略:`HandlerMapping`。

【腾讯】如何手写一个线程安全的单例?请分析枚举方式为何最安全?

枚举方式天然防止反射与反序列化破坏:① JVM禁止通过反射创建枚举实例;② 反序列化时直接返回枚举常量而非新建对象。源码级保障,无需额外处理。

【字节】观察者模式与发布-订阅模式的区别?

观察者模式中,观察者直接依赖主题对象;发布-订阅模式通过消息代理解耦发布者与订阅者。Spring事件是观察者模式,而Kafka是发布-订阅模式。
斌知网
蜀ICP备2026017620号-5