设计模式的原则,通常指的是 面向对象设计(OOD)的七大原则,它们是指导我们写出低耦合、高内聚、易扩展、易维护代码的准则。这些原则不仅适用于设计模式,更是日常编码中的"最佳实践"。
📐 七大核心原则概览
| 原则名称 | 英文/缩写 | 一句话解释 | 核心思想 |
|---|---|---|---|
| 单一职责原则 | Single Responsibility Principle (SRP) | 一个类只应有一个引起它变化的原因。 | 高内聚,一个类只负责一项职责。 |
| 开闭原则 | Open-Closed Principle (OCP) | 对扩展开放,对修改关闭。 | 用抽象 构建框架,用实现扩展细节。 |
| 里氏替换原则 | Liskov Substitution Principle (LSP) | 子类必须能够替换掉它们的父类。 | 尽量不重写父类方法,保持继承体系正确。 |
| 依赖倒置原则 | Dependency Inversion Principle (DIP) | 依赖抽象,不依赖具体。 | 高层模块不应依赖底层模块,两者都应依赖抽象。 |
| 接口隔离原则 | Interface Segregation Principle (ISP) | 建立单一接口,不要建立臃肿庞大的接口。 | 接口应该小而专,避免"胖接口"。 |
| 迪米特法则 | Law of Demeter (LoD) | 最少知道原则,一个对象应对其他对象有尽可能少的了解。 | 只与直接的朋友通信,降低耦合。 |
| 合成复用原则 | Composite Reuse Principle (CRP) | 优先使用对象组合(合成/聚合),而不是类继承。 | 组合/聚合复用已有功能,避免继承带来的强耦合。 |
🔬 原则详解与示例
1. 单一职责原则 (SRP)
一个类应该只有一个引起它变化的原因。
如果一个类承担了多个职责,那么任何一个职责的变化都可能影响其他职责,导致代码脆弱、不易维护。
-
反例 :
User类既有用户的属性,又有保存到数据库的方法。 -
正例 :
User只负责属性,UserDao负责数据库操作。
2. 开闭原则 (OCP)
对扩展开放,对修改关闭。
当需求变化时,应通过增加新代码来扩展行为,而不是修改已有的核心代码。这是所有原则的最终目标。
- 实现方式 :通过抽象(接口/抽象类)定义框架,通过具体类实现扩展。例如,支付接口
Payment,新增微信支付时只需实现该接口,而不修改原来支付宝支付的代码。
3. 里氏替换原则 (LSP)
子类可以扩展父类的功能,但不能改变父类原有的功能。
如果重写父类方法导致子类不能完全替换父类,则继承关系是错误的。例如,"正方形"继承"长方形"会违反LSP,因为修改正方形边长会导致面积行为变化。
- 关键点:子类方法的前置条件(参数)不能比父类更严格,后置条件(返回值/输出)不能比父类更宽松。
4. 依赖倒置原则 (DIP)
高层模块不应依赖低层模块,两者都应依赖抽象;抽象不应依赖细节,细节应依赖抽象。
传统的自顶向下设计会导致高层直接依赖底层,导致代码僵硬。DIP提倡面向接口编程。
- 示例 :
Computer类应依赖UsbInterface(抽象),而不是直接依赖Keyboard或Mouse类。这样更换外设时无需修改Computer类。
5. 接口隔离原则 (ISP)
客户端不应该被迫依赖于它不使用的方法。
一个"胖接口"会污染所有实现类。应将大接口拆分为多个小接口,每个接口只包含特定客户端需要的方法。
- 示例 :一个
Worker接口包含work()和eat()。对于机器人实现类,eat()是多余的。应拆分为Workable和Eatable接口。
6. 迪米特法则 (LoD)
只与你的直接朋友交谈,不与"陌生人"说话。
一个对象应尽可能少地了解其他对象的内部结构。减少方法之间的调用链条,降低耦合。
-
反例 :
a.getB().getC().doSomething();这导致a需要知道B和C的存在。 -
正例 :在
a中直接调用a.doSomething(),由a内部协调B和C。
7. 合成复用原则 (CRP)
尽量使用对象组合/聚合,而不是继承来达到复用的目的。
继承是"白盒复用"(父类细节对子类可见),组合是"黑盒复用"(只通过接口访问)。组合更灵活,耦合度更低。
- 示例 :
Car类需要引擎功能。应通过组合一个Engine对象,而不是继承Engine类。这样Car可以动态更换引擎类型。
💎 总结
| 原则 | 核心目的 | 一句话口诀 |
|---|---|---|
| 单一职责 | 类只做一件事 | 职责单一,不要"一专多能" |
| 开闭原则 | 不修改核心,只扩展 | 对扩展开放,对修改关闭 |
| 里氏替换 | 子类不破坏父类契约 | 子类型必须能替换父类型 |
| 依赖倒置 | 面向接口,不面向实现 | 依赖抽象,别依赖具体 |
| 接口隔离 | 接口要小而精 | 不要臃肿接口,按需隔离 |
| 迪米特法则 | 减少对象间直接耦合 | 只和朋友说话,别找陌生人 |
| 合成复用 | 组合优于继承 | 多用组合少用继承 |
这七大原则不是孤立存在的,它们相互补充。开闭原则 是终极目标,单一职责 是实现开闭的基础,里氏替换 和依赖倒置 是手段,接口隔离 和迪米特法则 是设计约束,合成复用是替代继承的更佳方案。