面试记录 2026-09-28
题目:使用哪种设计模式可以提高代码可维护性?
难度:difficulty/high
标签:arch/design-pattern, architecture/design, general/knowledge, difficulty/high
评分:⭐⭐⭐⭐☆(4/5)
我的回答
首先就是 Spring 中最核心的代理模式,通过代理对象对,在方法不改动的情况下对方法实行扩展,提高了代码的可维护性。
其次是我觉得是策略模式,策略模式中通过对于策略的扩展,然后提升整个代码的扩展能力,而不是每次去 if else 的去进行修改,这也是我用的比较多的一种模式。
再有就是创建者或者说工厂一类的,它把创建的创建对象简化了,提供了更简洁的能力,也更利于抽象化。
还有责任链模式。在一些判定的过程中,我会使用责任链模式,比较方便的扩展判定规则,更容易进行减少方法的变更,更容易进行修改,更容易进行扩展。
点评
优点:
- 覆盖了 4 个主流模式:代理、策略、工厂、责任链
- 每个模式都点出了核心收益:不改老代码扩展、替换 if-else、简化创建、判定规则扩展
- 提到"我用的比较多" —— 有实战痕迹
- 责任链的"判定规则"场景选得很有工程视角
不足:
- 每个模式只给了 1 句概括,没展开"为什么"和"怎么落地"—— 面试官会追问实际项目里的具体场景
- 少了 2 个对可维护性非常关键的模式:
- 观察者模式:事件驱动解耦,Spring 的 ApplicationEvent / @EventListener
- 模板方法:消除重复代码
- 外观模式:收敛复杂客户端为几个 API
- 没提"反过度设计"的边界—— 这是 senior 加分项
补充(可维护性模式的完整分类):
| 类别 | 模式 | 可维护性收益 |
|---|
| 减少变更 | 策略模式 | 加新策略不改老代码(OCP) |
| 代理模式 | AOP 横切逻辑从业务代码剥离 |
| 观察者模式 | 事件解耦,新增监听不动发送端 |
| 消除重复 | 模板方法 | 提取算法骨架,子类只实现差异 |
| 简化调用 | 工厂模式 | 封装复杂创建过程 |
| 建造者模式 | 复杂对象分步构建,可读性高 |
| 外观模式 | 收敛复杂子系统为几个 API |
| 规则可插拔 | 责任链模式 | 新增规则节点即可,不改主流程 |
| 动态增强 | 装饰器模式 | 运行时组合功能,不用继承爆炸 |
完整讲解
第一部分:知识重点剖析
核心考点定位:考察对设计模式实际工程价值的理解,特别是"可维护性"这一设计目标的落地方式。
知识点拆解:
- 可维护性的本质:降低变更成本—— 每次需求变化时,改动的代码越少、影响范围越小、回归成本越低,可维护性就越高。
- 减少变更范围的模式(OCP 落地):
- 策略模式:if-else 泛滥的场景(不同支付方式、不同通知渠道、不同优惠计算规则),加新策略不改老代码
- 代理模式:横切关注点(日志、事务、权限、限流)通过 AOP 剥离,业务代码保持纯粹
- 观察者模式:跨模块协作(订单支付完成后触发积分、通知、库存回滚),新增监听器完全不动发送端
- 消除重复代码的模式(DRY 原则):
- 模板方法:把"参数校验 → 业务执行 → 后置日志"这种重复骨架抽成模板,子类只实现差异部分(如 JdbcTemplate)
- 工厂模式:封装复杂对象创建过程,避免到处 new + 初始化
- 建造者模式:复杂对象分步构建,比构造函数更好读
- 简化调用点的模式(KISS 原则):
- 外观模式:把复杂子系统收敛为几个 API(如 RestTemplate、JdbcTemplate)
- 责任链模式:新增规则节点即可,不改主流程(参数校验链、权限校验链、支付回调链)
- 动态增强的模式:
- 装饰器模式:运行时组合功能,不用继承爆炸(如 IO 流装饰器、代理增强)
- 回答框架(senior 加分项):
- 从三个维度选模式:减少改动范围(策略/代理/观察者)、消除重复(模板/工厂/建造者)、简化调用点(外观/责任链)
- 实际项目用得最多的三个:策略模式、观察者模式、责任链模式
- 克制使用:简单业务不要为了用模式而用模式,一行 if-else 比抽象策略类更易读。判断标准:如果一年内这个分支大概率要改 3 次以上,才值得抽象成模式
- 反过度设计的标志:
- 简单 CRUD 强用策略模式,加一层抽象反而绕
- 只有两个实现也上策略接口,未来扩展性"预期"存在
- 大量用工厂+策略+建造者堆叠,形成"过度抽象"
第二部分:考察方向与延伸递进
考察方向:
- 深度:模式的实际收益与反例
- 广度:模式之间的选型与组合
- 应用:实际项目中的落地经验和反思
延伸递进面试题:
- 策略模式和 if-else 的分界线在哪?什么情况该抽象成策略?
- 解答要点:如果一年内这个分支大概率要改 3 次以上,才值得抽象成策略。判断维度:① 分支是否会持续扩展(业务增长);② 分支逻辑是否高度相似(可以抽象公共接口);③ 分支是否会被多处复用(策略类能注入到其他模块);④ 分支逻辑是否频繁变更(策略类能独立测试)
- 观察者模式在 Spring 中如何落地?如何避免"事件风暴"?
- 解答要点:Spring 用 ApplicationEvent + ApplicationListener + @EventListener 实现观察者,@TransactionalEventListener 结合事务。避免事件风暴:① 事件命名规范(按领域分类);② 一个事件只表达一个领域事实;③ 用类型参数而不是消息体(避免事件过大);④ 监听器之间不产生级联事件(避免循环)
- 责任链模式和策略模式有什么区别?什么场景选哪个?
- 解答要点:策略是"多个候选选一个执行"(如不同支付方式选一个),责任链是"多个节点依次执行"(如参数校验链、权限校验链、风控规则链)。选策略:一次调用只走一个实现;选责任链:一次调用要走多个节点
第三部分:面试者参考回答(300-600 字口语化)
面试官您好,可维护性的核心是降低变更成本——每次需求变化时,改动的代码越少、影响范围越小、回归成本越低,可维护性就越高。我从三个维度选模式:
第一维度是减少变更范围,对应开闭原则 OCP。最常用的是策略模式,业务分支多的场景(不同支付方式、不同通知渠道、不同优惠计算规则)特别适合——加新策略不改老代码,比 if-else 好维护太多。其次代理模式(Spring AOP 核心)把横切关注点(日志、事务、权限、限流)从业务代码剥离,业务代码保持纯粹。第三个是观察者模式,Spring 里用 ApplicationEvent + @EventListener,跨模块协作(订单支付完成后触发积分、通知、库存回滚)用事件驱动,新增监听器完全不动发送端,这是解耦利器。
第二维度是消除重复代码,对应 DRY 原则。模板方法把"参数校验 → 业务执行 → 后置日志"这种重复骨架抽成模板,子类只实现差异部分,Spring 的 JdbcTemplate、RestTemplate 都是典型。工厂模式和建造者模式把复杂对象创建收敛,比到处 new + 初始化好读太多。
第三维度是简化调用点,对应 KISS 原则。外观模式把复杂子系统收敛为几个 API(如 RestTemplate 收敛了 HttpURLConnection 的复杂操作)。责任链模式特别适合规则判定场景(参数校验链、权限校验链、风控规则链、支付回调链),加新规则节点即可,不改主流程,这是我认为最容易落地的可维护性模式。
装饰器模式是动态增强,运行时组合功能不用继承爆炸,IO 流、代理增强都是典型。
实际项目里用得最多的三个:策略模式(业务分支多、if-else 泛滥时)、观察者模式(跨模块协作、需要解耦时)、责任链模式(判定规则、校验链、回调处理)。
但克制使用很重要——简单业务不要为了用模式而用模式,一行 if-else 比抽象策略类更易读。判断标准:如果一年内这个分支大概率要改 3 次以上,才值得抽象成模式。反过度设计的标志:简单 CRUD 强用策略模式、只有两个实现也上策略接口、大量工厂+策略+建造者堆叠形成"过度抽象",这些都会让代码更难维护。