设计模式的 7 大基本原则有哪些?
2026年01月25日
一则或许对你有用的小广告
欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于
Spring AI + Spring Boot3.x + JDK 21..., 点击查看; - 《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot3.x + JDK 17..., 点击查看项目介绍; 演示链接: http://116.62.199.48:7070/; - 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/
面试考察点
当面试官询问设计模式的基本原则时,他们的核心考察点并不仅仅是让你背诵七个名字,而是希望你:
- 理解设计模式的灵魂:考察你是否明白所有设计模式背后共通的设计哲学和指导思想,而不仅仅是死记硬背23种模式的实现。
- 评估代码设计能力:通过你对原则的理解,判断你在日常编码中是否具备写出高内聚、低耦合、易复用、易扩展代码的意识和能力。
- 考察知识体系完整性:确认你对面向对象设计(OOD)的核心思想有系统性的认知,这些原则是 OOD 的基石。
- 探究实践与理论的结合:面试官不仅仅想知道“是什么”,更想知道你能否举例说明如何运用这些原则解决实际问题,以及违反原则会导致什么后果。
核心答案
设计模式的七大基本原则,也称为 SOLID + 2 原则,是指导我们进行高质量软件设计的核心思想。它们分别是:
- 单一职责原则 (Single Responsibility Principle, SRP):一个类只应有一个引起它变化的原因。
- 开闭原则 (Open-Closed Principle, OCP):软件实体(类、模块、函数)应该对扩展开放,对修改关闭。
- 里氏替换原则 (Liskov Substitution Principle, LSP):所有引用基类的地方必须能透明地使用其子类的对象,而程序的行为不会发生改变。
- 接口隔离原则 (Interface Segregation Principle, ISP):客户端不应该被迫依赖它不使用的接口。一个类对另一个类的依赖应该建立在最小的接口上。
- 依赖倒置原则 (Dependency Inversion Principle, DIP):高层模块不应依赖低层模块,二者都应依赖其抽象。抽象不应依赖细节,细节应依赖抽象。
- 迪米特法则 (Law of Demeter, LoD),又称最少知识原则:一个对象应该对其他对象保持最少的了解。只与直接的朋友通信。
- 合成复用原则 (Composite Reuse Principle, CRP):尽量使用对象组合(has-a)/聚合(contains-a),而不是继承(is-a)关系来达到复用的目的。
深度解析
这些原则共同的目标是构建可维护、可复用、灵活且健壮的软件系统。
-
单一职责原则 (SRP)
- 核心:一个类只负责一项职责。如果类承担了过多职责,那么任何一个职责的变化都可能影响该类,导致脆弱的设计。
- 示例:一个
UserService类,如果同时负责用户信息持久化(saveToDB)和发送通知邮件(sendEmail),就违反了 SRP。应将持久化和邮件服务拆分为两个独立的类,UserService仅负责业务逻辑协调。 - 最佳实践:在微服务架构中,一个服务的边界定义正是 SRP 的宏观体现。
-
开闭原则 (OCP)
- 核心:通过 抽象 和 多态 来实现。当需求变化时,我们通过增加新的代码(如新的子类、实现类)来扩展功能,而非修改现有的、稳定的代码。
- 代码示例:
// 抽象:对扩展开放 interface DiscountStrategy { double apply(double price); } // 具体实现:可以不断扩展 class VIPDiscount implements DiscountStrategy { @Override public double apply(double price) { return price * 0.8; } } class FestivalDiscount implements DiscountStrategy { @Override public double apply(double price) { return price - 50; } } class Order { private DiscountStrategy strategy; // 依赖抽象 public void setStrategy(DiscountStrategy strategy) { this.strategy = strategy; } public double calculateFinalPrice(double originalPrice) { return strategy.apply(originalPrice); // 使用抽象 } } - 常见误区:OCP 不是绝对的,100% 的关闭不可能。应关注于识别出最有可能变化的区域,并为之设计稳定的抽象。
-
里氏替换原则 (LSP)
- 核心:它是对继承关系的严格约束。子类可以扩展父类的功能,但不能改变父类原有的功能(行为)。
- 经典反例:
Square继承Rectangle。Rectangle有setWidth和setHeight方法,但Square的这两个方法会相互影响,改变了父类“长宽可独立设置”的行为约定,导致在使用父类Rectangle的地方替换为Square会出现错误。 - 实践:在重写方法时,子类的前置条件(对输入的要求)不能比父类更严格,后置条件(对输出的承诺)不能比父类更宽松。
-
接口隔离原则 (ISP)
- 核心:避免 “胖接口”。将庞大的接口拆分为更小、更具体的接口,让客户端只需知道它们关心的方法。
- 示例:一个
Animal接口定义了eat(),fly(),swim()方法。对于Dog类来说,实现fly()是毫无意义的“接口污染”。应拆分为Eatable,Flyable,Swimmable等多个接口。
-
依赖倒置原则 (DIP)
- 核心:它是实现松耦合的关键。程序的依赖关系应从“具体”倒置为“抽象”。
- 对比:传统自上而下的设计是:高层模块
Application-> 依赖 -> 中层模块Logger-> 依赖 -> 低层模块FileWriter。倒置后:Application依赖Logger接口,FileLogger(实现类)和DatabaseLogger(实现类)也依赖同一个Logger接口。控制权从低层(FileWriter)转移到了高层(Application)。 - 框架体现:Spring 框架的 控制反转(IoC) 和 依赖注入(DI) 是 DIP 原则的完美实践。我们只依赖
@Service、@Repository这样的抽象,由容器提供具体实例。
-
迪米特法则 (LoD)
- 核心:降低类之间的耦合度。一个类应该尽量减少对其他类内部结构的了解。
- “朋友” 定义:出现在成员变量、方法参数、方法返回值中的类称为直接朋友。出现在方法内部的局部变量中的类不是直接朋友。
- 反例:
A.getB().getC().doSomething()这就是典型的 “链式调用”,A对C产生了依赖,耦合度变高。更好的方式可能是由B提供一个代理方法。
-
合成复用原则 (CRP)
- 核心:继承是 白箱复用(破坏封装性),组合/聚合是 黑箱复用(保持封装性)。
- 优势:组合关系比继承关系更灵活。可以在运行时动态改变行为(通过注入不同的组件),避免了继承体系的无限膨胀和僵化。
- 示例:
Car类不应该继承Engine类(“车是一个引擎”?这说不通),而应该组合一个Engine实例(“车有一个引擎”)。
总结
七大设计原则是构建优秀软件的导航图,其核心共同点在于 通过抽象和中间层来隔离变化、降低耦合,其中 依赖倒置(DIP) 是许多原则(如开闭原则、里氏替换)能够实现的关键架构保障。在实际项目中,应灵活运用这些原则,而非教条地遵循,最终目标是交付易于维护和扩展的高质量代码。