【设计模式笔记07】:迪米特法则
文章目录
- 迪米特法则 (LoD)
- 1. 定义
- 2. “朋友”的界定
- 3. 典型应用
- 4. 实例:CRM系统界面控件交互
迪米特法则 (LoD)
1. 定义
迪米特法则,也称为最少知识原则 (LKP),它有多种定义方式,但核心思想都是一致的。
-
定义1 (最通俗的): 不要和“陌生人”说话。 (Don’t talk to strangers.)
- 这个定义非常形象地表达了原则的精髓。一个对象应该尽可能少地了解其他对象的内部细节。
-
定义2 (进一步解释): 只与你的直接朋友通信。
- 这引出了一个关键概念:“朋友”。接下来会详细解释什么是“朋友”。
-
定义3 (最正式的): 每一个软件单位对其他的单位都都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
- 这里的“软件单位”可以指一个类、一个模块或一个函数。这个定义强调了知识的“局部化”,避免信息在系统中不必要地传播。
2. “朋友”的界定
理解迪米特法则的关键在于理解什么是“直接朋友”。
-
耦合与朋友关系:
- 在面向对象的世界里,每个对象都会与其他对象有耦合关系。只要两个对象之间有耦合关系,就说这两个对象之间是朋友关系。
- 耦合的方式很多,如依赖、关联(组合与聚合)等。
-
直接朋友 (Direct Friends):
- 对于一个类(比如类
A)来说,它的“直接朋友”包括以下几种:- 类
A自身的成员变量所引用的对象。 - 类
A中某个方法的方法参数所引用的对象。 - 类
A中某个方法的方法返回值所引用的对象。 - 类
A自身的对象(this)。
- 类
- 对于一个类(比如类
-
“陌生人” (Strangers):
- 迪米特法则要求,陌生的类最好不要以局部变量的形式出现在类的内部。
- 一个类只与它的直接朋友通信,而以局部变量形式出现的类不是该类的直接朋友。
- 典型的违反场景: 连续的
.调用,如a.getB().getC().doSomething()。在这个链式调用中,a是朋友,但b和c对象对于当前类来说就是“陌生人”。我们通过朋友a的“介绍”认识了陌生人b,又通过b认识了c,这违反了“只和直接朋友说话”的原则。
3. 典型应用
- 外观模式 (Facade Pattern) 和 中介者模式 (Mediator Pattern) 都是迪米特法则的典型应用。
- 外观模式: 为一个复杂的子系统提供一个统一的、简化的接口。客户端只需要与这个外观接口(直接朋友)交互,而不需要了解子系统内部众多类(陌生人)的复杂关系。
- 中介者模式: 用一个中介对象来封装一系列的对象交互。各个对象不再直接相互引用,而是都只与中介者(直接朋友)通信,由中介者协调它们之间的交互,将网状的复杂关系变为星状的简单关系。
4. 实例:CRM系统界面控件交互
- a. 初始设计 (违反LoD)
- 场景: 一个CRM系统包含很多业务操作窗口,在这些窗口中,某些界面控件之间存在复杂的交互关系。一个控件事件的触发将导致多个其他界面控件产生响应。
- 具体例子: 当一个按钮
Button被单击时,对应的列表框List、组合框ComboBox、文本框TextBox和文本标签Label等都将发生改变。 - 设计方案: 在初始设计中,这些界面控件之间直接进行交互,形成了一个复杂的网状结构。

-
问题分析:
- 高耦合:
Button类直接了解并调用了List、ComboBox等多个控件的细节,反之亦然。每个控件都认识了太多“朋友”,导致它们之间紧密耦合。 - 扩展性差: 如果此时需要增加一个新的界面控件(例如一个
CheckBox),并且它需要与现有控件交互,那么可能需要修改多个与之交互的其他控件的源代码,系统扩展性较差,需要重构。
- 高耦合:
-
b. 重构后的设计 (遵循LoD)
- 重构目标: 降低界面控件之间的耦合度,使它们不再直接交互。
- 解决方案: 引入一个中介类 (Mediator),专门用于控制界面控件之间的交互。

图片描述:重构后的UML对象图。
Button,List,Label,ComboBox,TextBox不再相互关联,而是都只与中心的Mediator类发生关联,形成了一个星型结构。
- 工作流程:
- 所有的控件(如
Button)都只认识中介者Mediator这个“直接朋友”。 - 当
Button被点击时,它不会直接去操作List或TextBox,而是通知中介者Mediator:“我被点击了”。 - 中介者
Mediator接收到请求后,再由它来完成对其他控件(List,TextBox等)的调用和协调。
- 所有的控件(如
- 重构后优点:
- 低耦合: 界面控件之间不再产生直接引用,它们都只依赖于中介者。
- 高内聚: 每个控件只负责自己的行为和通知中介者,而复杂的交互逻辑被封装在中介者内部。
- 易于维护和扩展: 如果要修改交互逻辑,只需要修改中介者类。如果要增加新的控件,也只需要让它和中介者交互即可,对现有控件类的影响降到了最低。这完美地体现了迪米特法则的精神。
