面试记录 2026-09-28
题目:设计模式的7大基本原则有哪些?
难度:difficulty/high
标签:arch/design-pattern, architecture/design, general/knowledge, difficulty/high
评分:⭐⭐☆☆☆(2/5)
我的回答
设计模式的七大基本原则,开闭原则。想不起来了,我就记得对修改关闭,对继承开放开闭原则,然后是还有啥呀?
点评
优点:
- 记得开闭原则 OCP 这个概念
- 大方向记得"对修改关闭"
不足(严重):
- 开闭原则定义说错了:"对修改关闭,对继承开放" ❌ 应该是"对修改关闭,对扩展开放"(Open/Closed Principle)—— 这是经典定义,说错会被面试官追问"什么是扩展、扩展怎么实现的"
- 7 大原则只记得 1 个,剩下 6 个想不起来 —— 这是本题的核心失分点
- SOLID 五大原则是设计原则的骨架(Single / Open / Liskov / Interface / Dependency),这五个必须能完整背诵
补充(7 大原则完整清单,必须背下来):
| # | 原则 | 缩写 | 一句话 |
|---|
| 1 | 单一职责原则 | SRP | 一个类只做一件事 |
| 2 | 开闭原则 | OCP | 对修改关闭,对扩展开放 |
| 3 | 里氏替换原则 | LSP | 子类能替换父类且程序逻辑不变 |
| 4 | 依赖倒置原则 | DIP | 面向接口编程,都依赖抽象 |
| 5 | 接口隔离原则 | ISP | 客户端不应被迫依赖不用的接口 |
| 6 | 合成复用原则 | CRP | 优先组合,而不是继承 |
| 7 | 迪米特法则 | LOD | 最少知识原则,只和直接的朋友谈 |
SOLID 五大原则速记:
- S: Single Responsibility
- O: Open/Closed
- L: Liskov Substitution
- I: Interface Segregation
- D: Dependency Inversion
完整讲解
第一部分:知识重点剖析
核心考点定位:考察对面向对象设计原则的系统掌握,特别是 SOLID 五大原则的完整理解和工程应用。
知识点拆解:
- SOLID 五大原则(核心中的核心):
- Single Responsibility(单一职责原则 SRP):一个类只做一件事(一个类只承担一个引起变化的原因)
- Open/Closed(开闭原则 OCP):对修改关闭,对扩展开放(新增功能不改老代码)
- Liskov Substitution(里氏替换原则 LSP):子类能替换父类出现且程序逻辑不变(子类不能违反父类契约)
- Interface Segregation(接口隔离原则 ISP):客户端不应被迫依赖不用的接口(接口要小而专)
- Dependency Inversion(依赖倒置原则 DIP):面向接口编程,高层不依赖低层,都依赖抽象
- 另外两个补充原则:
- Composite Reuse Principle(合成复用原则 CRP):优先组合,而不是继承("合成优于继承")
- Law of Demeter(迪米特法则 LOD):最少知识原则("只和直接的朋友谈",减少对象间的耦合)
- 每个原则的典型违反案例:
- SRP:一个类里既有 CRUD 又有导出 Excel 又有权限校验 —— 应该拆
- OCP:加个"信用卡支付"要改 Pay 方法里的 if-else —— 应该用策略模式
- LSP:Rectangle 继承 Shape,子类覆写方法时抛异常 —— 子类应该能替换父类
- DIP:UserService 直接 new MySqlUserDao —— 应该 @Autowired UserDao
- ISP:OrderService 接口同时有 create/cancel/export/notify —— 应该拆小
- CRP:用继承实现"可序列化用户" —— 应该用组合 Serializer serializer
- LOD:a.getB().getC().doSomething() 链条太长 —— 应该封装
- "扩展"到底是什么(回答 OCP 时要能答):
- 用继承扩展:子类新增方法
- 用接口 + 策略扩展:新实现类注册到策略容器
- 用注解 + 反射扩展:定义规范(注解),运行时扫描匹配
- 用模板方法扩展:子类覆写模板钩子
- 用装饰器扩展:装饰对象动态增强
- 原则之间的关系:
- SRP 是基础(单一职责),其他原则建立在它之上
- OCP 是目标(对修改关闭),需要 LSP/DIP/ISP/CRP 来支撑
- LSP 保证继承的健壮性
- DIP 是 OCP 的工程手段(面向接口才能扩展)
- ISP 让 DIP 更纯粹(小接口更好用)
- CRP 是实现 OCP 的替代方案(组合优于继承)
第二部分:考察方向与延伸递进
考察方向:
- 深度:每个原则的边界条件、反例识别
- 广度:原则之间的关联与冲突
- 应用:实际项目中的重构经验
延伸递进面试题:
- 开闭原则的"扩展"具体指哪些方式?策略模式和模板方法哪种更符合开闭原则?
- 解答要点:扩展指不改老代码而增加功能,包括继承子类新增方法、接口 + 策略新增实现类、注解 + 反射匹配、模板方法覆写钩子、装饰器动态增强。模板方法更适合"算法骨架固定、细节可变化"的场景(如 JdbcTemplate.execute),策略模式更适合"算法整体可替换"的场景(如不同支付方式的 Pay 接口)。模板方法扩展更受限,策略模式扩展更灵活
- 里氏替换原则和接口隔离原则经常冲突,如何解决?
- 解答要点:LSP 要求"子类能替换父类",但 ISP 要求"接口要小而专"。解决方式是先按 ISP 拆小接口,每个小接口内部再按 LSP 继承扩展。例如 Order 相关接口拆成 OrderCreateService、OrderQueryService、OrderExportService,每个接口单独扩展而不互相耦合
- 单一职责和迪米特法则如何在实践中落地?有什么反例?
- 解答要点:SRP 落地方法是给类起个"能一句话说清的职责名",如果名字里出现"和"(如 User 和 Order Service),大概率违反 SRP。LOD 落地方法是控制对象间调用链不超过 2 层(a.getB().doX() 已经算极限)。反例:一个 Service 里既有业务逻辑又有 Excel 导出又调用了 3 个下游的下游 API
第三部分:面试者参考回答(300-600 字口语化)
面试官您好,设计模式的 7 大基本原则我一般分成两组来记,核心是 SOLID 五大原则,另外补充合成复用原则和迪米特法则。
SOLID 五大原则:
第一,单一职责原则 SRP(Single Responsibility):一个类只做一件事,一个类只承担一个引起变化的原因。反例是一个类里既有 CRUD 又有导出 Excel 又有权限校验,应该拆。实际落地方法是给类起个"能一句话说清的职责名",如果名字里出现"和"字(如 User 和 Order Service),大概率违反 SRP。
第二,开闭原则 OCP(Open/Closed):对修改关闭,对扩展开放,新增功能不改老代码。这个"扩展"具体有几种方式:继承子类新增方法、接口 + 策略新增实现类、注解 + 反射匹配、模板方法覆写钩子、装饰器动态增强。反例是加个"信用卡支付"要改 Pay 方法里的 if-else,应该用策略模式,加个 CreditCardPay implements Pay。
第三,里氏替换原则 LSP(Liskov Substitution):子类能替换父类出现且程序逻辑不变,子类不能违反父类契约。反例是 Rectangle 继承 Shape,但子类覆写方法时抛异常,破坏了父类契约。这个原则是继承的健康保障。
第四,接口隔离原则 ISP(Interface Segregation):客户端不应被迫依赖不用的接口,接口要小而专。反例是 OrderService 接口同时有 create/cancel/export/notify,业务方只需要 create,应该拆成 OrderCreateService。这个原则和 LSP 有时会冲突,解决办法是先按 ISP 拆小接口,每个小接口内部再按 LSP 继承扩展。
第五,依赖倒置原则 DIP(Dependency Inversion):面向接口编程,高层不依赖低层,都依赖抽象。反例是 UserService 直接 new MySqlUserDao,应该 @Autowired UserDao。这个原则是开闭原则的工程手段——只有面向接口编程,才能通过"新增实现类"来扩展。
另外两个补充原则:
第六,合成复用原则 CRP(Composite Reuse):优先组合,而不是继承,也叫"合成优于继承"。反例是用继承实现"可序列化用户",应该用组合 User 里注入 Serializer。这个原则是实现开闭原则的替代方案,组合比继承更灵活。
第七,迪米特法则 LOD(Law of Demeter):最少知识原则,"只和直接的朋友谈",减少对象间的耦合。反例是 a.getB().getC().doSomething() 链条太长,应该封装成 a.doX()。落地方法是控制对象间调用链不超过 2 层。
原则之间的关系:SRP 是基础(单一职责),其他原则建立在它之上;OCP 是目标(对修改关闭),需要 LSP/DIP/ISP/CRP 来支撑;DIP 是 OCP 的工程手段(面向接口才能扩展);ISP 让 DIP 更纯粹(小接口更好用)。
实际工程中我一般会先用 SOLID 检查设计,再用设计模式落地——比如用策略模式实现 OCP、用工厂模式配合 DIP、用模板方法保证 LSP。这三大问题(SRP + OCP + DIP)在实际重构中用得最多。