面向对象中的模块模块化的九个原则降低访问耦合全局变量有害(Global Variables Consider Harmful)显式优于隐式(To be Explicit)不要重复代码(Do not Repeat)面向接口编程(Programming to Interface)/ 契约式设计(Design by Contract)迪米特法则 / 最少知识原则(The Law of Demeter)接口隔离原则(Interface Segregation Principle)降低继承耦合里氏替换原则(Liskov Substitution Principle)优先使用组合而非继承(Favor Composition Over Inheritance)提高内聚单一职责原则(Single Responsibility Principle)
- 模块化的九个原则
- 对给定的示例,发现其所违反的原则,并进⾏修正
面向对象中的模块
最重要的是类.
对于类来说, 类的供接口就是其所有公有的成员变量和成员方法, 可以被别的类直接访问, 代表该类愿意与他人合作的一个协议; 类的需接口则是其在实现中使用到的其他类及其相关协议.
模块化的九个原则
对给定的示例要能发现其所违反的原则并修正
面向对象方法下的耦合主要可分为访问耦合与继承耦合.
模块化设计中常见的设计原则:
编号 | 原则 | 中文名称 | 核心目标 |
1 | Global Variables Bad | 全局变量有害 | 减少隐式耦合 |
2 | Be Explicit | 显式优于隐式 | 提高代码清晰度 |
3 | Do Not Repeat | 不要重复代码 | 降低维护成本 |
4 | Programming to Interface | 面向接口编程 | 解耦依赖, 支持替换和扩展 |
5 | Law of Demeter | 迪米特法则 | 减少模块了解彼此的细节 |
6 | Interface Segregation | 接口隔离原则 | 接口要细粒度 |
7 | Liskov Substitution | 里氏替换原则 | 保证继承正确性与一致性 |
8 | Favor Composition | 优先组合而非继承 | 灵活扩展, 避免继承弊端 |
9 | Single Responsibility | 单一职责原则 | 模块关注单一功能, 易维护 |
降低访问耦合

全局变量有害(Global Variables Consider Harmful)
针对公共耦合
含义:尽量避免使用全局变量.
理由:
- 全局变量会引起模块之间的隐式耦合;
- 修改难以追踪, 调试困难;
- 破坏封装性, 使代码难以维护.
示例:一个模块修改了全局状态, 另一个模块也依赖该状态, 结果可能不一致, 甚至产生错误.
显式优于隐式(To be Explicit)
针对隐式耦合
含义:程序的行为应尽可能明确、可读, 不应隐藏在复杂逻辑或默认规则中.
理由:
- 增强可读性和可维护性;
- 减少误解和错误行为.
示例:函数的输入参数应清晰地说明用途, 而不是依赖外部状态或隐式数据.
不要重复代码(Do not Repeat)
针对重复耦合
也称 DRY 原则(Don’t Repeat Yourself)
含义:相同的逻辑应封装成一个模块或函数, 避免重复代码.
理由:
- 降低维护成本;
- 修改时只需改一处, 避免遗漏;
- 增强一致性.
示例:计算折扣的逻辑不要在多个地方重复出现, 应提取为一个公共函数.
面向接口编程(Programming to Interface)/ 契约式设计(Design by Contract)
针对访问耦合
含义:依赖接口(抽象)而不是实现类(依赖倒置原则DIP).
理由:
- 解耦, 提高灵活性;
- 更容易替换或扩展实现;
- 有助于单元测试和依赖注入.
示例:PaymentProcessor 接口定义支付操作, 而 AliPay 和 WeChatPay 是具体实现.
迪米特法则 / 最少知识原则(The Law of Demeter)
针对访问耦合
降低控制耦合的深度
含义:一个模块/对象只应该与直接的朋友通信, 不应该了解太多“陌生对象”的内部细节, 限制调用链长度在2以内.
具体说法:
只调用以下之一:
- 本对象的方法;
- 参数对象的方法;
- 直接创建的对象的方法;
- 直接成员变量的方法(但不要再访问其成员的成员).
理由:
- 降低耦合;
- 防止对象过度依赖其他模块的结构.
- 级联调⽤的问题: 难以应对变更+代码难理解. 应对的⽅法: 采⽤委托式调⽤, 限制单次调用链的深度.
示例(违反法则):
order.getCustomer().getAddress().getCity()
就是典型的“深入访问”, 应避免. 当一个人想要遛狗, 千万不要命令狗的腿去走, 而是人命令狗, 让狗去命令它自己的腿.
接口隔离原则(Interface Segregation Principle)
针对访问耦合
含义:客户端不应依赖它不需要的接口. 换言之, 接口应该小而专一, 而不是庞大而笼统.
理由:
- 降低实现类的负担;
- 避免空实现或无关依赖(即不必要的访问耦合).
示例:
不要定义一个 IMachine 接口包含 print()、scan()、fax(), 而应拆分为 IPrinter、IScanner 等更细粒度接口.
降低继承耦合

里氏替换原则(Liskov Substitution Principle)
针对继承耦合
含义:子类对象应该能够替换父类对象, 并保持原有行为的正确性.
理由:
- 确保继承关系成立;
- 避免多态行为异常.
不使用继承时耦合度为N, 一棵满足里氏替换原则的继承树的耦合度为1, 即在符合LSP的前提下, 继承树内部的类间耦合是可以忽略的, 有效降低了耦合; 而不符合LSP时使用继承甚至还增加了耦合(调用者需要区分父类和所有子类, 耦合度N+1).
违反示例:
Bird 是 Animal, Penguin 是 Bird, 但 Penguin.fly() 不成立, 说明设计不当.
优先使用组合而非继承(Favor Composition Over Inheritance)
针对继承耦合
在希望复用代码又难以满足里氏替换原则时, 一般用组合代替继承
含义:优先通过组合(“有一个”)关系来扩展功能, 而不是通过继承(“是一个”)关系.
理由:
- 继承耦合紧密, 容易导致“脆弱基类问题”;
- 组合更灵活, 可在运行时动态切换行为.
示例:
用 Car 拥有一个 Engine 对象, 而不是 Car 继承自 Engine.
提高内聚
方法内聚, 类的内聚, 子类和父类的继承内聚
单一职责原则(Single Responsibility Principle)
提高内聚
含义:一个模块(类/函数)应该只负责一类功能, 不要同时处理多个职责.
理由:
- 提高可维护性和可测试性;
- 修改时影响范围小.
示例:
一个类如果同时处理“用户登录逻辑”和“日志记录逻辑”, 就违反了单一职责, 应拆分为两个类.