面向对象设计(OOD):迪米特法则(LoD)

迪米特法则(LoD:Law of Demeter)又叫最少知识原则(LKP:Least Knowledge Principle ),是由Ian Holland于1987年提出来的,指的是一个类/模块对其他的类/模块有越少的了解越好。简言之:talk only to your immediate friends(只跟你最亲密的朋友交谈),不跟陌生人说话。

高内聚低耦合

软件设计有一个meta rule:高内聚,低耦合。

内聚是从功能角度来度量模块内的联系紧密度,一个好的内聚模块应该恰好专注于完成一个事情,紧密相关的功能代码才应该放置在一起。

耦合是软件结构中模块间的关联复杂度,是依赖关系的度量,当然模块间的依赖是无法完全避免的,孤立的模块可能也没什么卵用,但软件工程师应当树立一个意识:即吾辈应该向简化依赖关系的方向努力。

在软件设计中,经常用内聚和耦合作为衡量模块独立性的尺度,许多OOD设计原则都是为了帮助达成这2个设计目标,松散、复杂的依赖关系是可信、可读性、可维护性的大敌。

为什么要降低耦合性?

迪米特法则的初衷就是为了降低耦合。降低模块间的联系度,有利于提升模块的独立性,高独立性的模块受别的模块改动的影响小,如果修改一个模块,很多模块受影响(比如引起编译错误,或者需要重新构建),则是一件蛋疼的事。

模块间的耦合强,意味着修改模块A,所有依赖A的其他模块,都需要配合修改和重新构建,需要协作的事情总是比可单独完成的事情更棘手,复杂性是稳定性的大敌。相互block会导致延误项目进展,好的设计应该追求更高的独立性,高独立性意味花在沟通上的成本更低,独立性跟复杂性几乎是互斥的,越耦合越复杂。

怎么降低耦合性?

1. 单一职责让代码可读性更强,可维护性更好,且更容易被复用,单一职责的理念贯穿于软件设计的各个方面,不仅仅适用于类和函数的设计,也适用于模块划分,文件拆分。比如你应该让一个函数专注于一件事情从而提高它的健壮性和可复用性,比如你不应该设计巨类从而避免让你为类命名而头疼,比如你应该让文件保持简洁短小,而不是随意的把不相干的东西塞进来像垃圾一样堆在一起。单一职责为软件设计提高良好的指引,大多数STD C API都符合单一职责的原则,从最初的STD C API发展至今已有几十年,但这些API无论数量还是函数原型都很少变化(只是为了安全加了一些防护,比如strncpy, strcat_s),可见,设计良好的接口才会有强盛的生命力。

2. 设计类的时候,要秉持最少知识原则,这表示应该降低成员的访问权限,尽量减少接口暴露:考虑私有化成员变量,不需要公开的成员函数不公开。

3. 不需要被其他模块调用的全局函数,应该添加static修饰从而将它限于模块内,避免污染全局空间,维护最小够用的接口集,最小的接口集往往代表着最小的依赖。

4. 在编写c文件的时候,要谨慎处理include,仅需include必须的头文件,遵从头文件包含自给自足原则(包含必要的头文件,且只包含必须的头文件)。包含不必要的头文件,不仅仅意味着更长的编译时间(源文件的预处理阶段展开会得到更多内容),而且意味着该文件依赖的任何其他文件的修改都会导致它的重新构建。

5. 消息机制是模块解耦的惯用手段,不仅限于跨进程的消息机制,也包括进程内模块间的消息机制。模块A与B要耦合,则可能需要相互包含头文件,相互识别对方模块的符号,消息机制提供了另一种思路,可以通过发送消息的方式,去驱动另一个模块doSomething,也可以通过消息,把模块内的信息发送给其他模块。

6. 门面模式(Facede)和中介者模式(Mediator)都是迪米特法则的应用实例,它们都源自生活。门面模式解决的是将一对多转变为更简单的一对一,比如开一个公司,原先需要去各个不同的政府部门办各种证明,改革之后,只有一个部门对外接口,这种好处是显而易见的,它把复杂性从外部转移到了模块内部,政府内部封装逻辑并暴露单一界面。中介者模式可以用房屋买卖来举例,它避免房屋买卖双方直接沟通,中介居中沟通协调,简化耦合松散的关系。门面和中介两种模式稍微有些不同,门面更多的是一个模块要call或者use多个其他模块,是单向的;而中介模式通过引入中介者这个角色,解决了相互call或者use的依赖问题。

不要盲信

迪米特法则不希望模块或类之间建立直接的联系,如果需要也希望通过类似友元的方式来完成,因此它有可能造成大量中介类,这些类之所以存在完全是为了传递类之间的相互调用关系,这在一定程度上增加了系统的复杂度。

另外,遵循类之间的迪米特法则会是一个系统的局部设计简化,因为每一个局部都不会和远距离的对象有直接的关联。但是,这也会造成系统的不同模块之间的通信效率降低,也会使系统的不同模块之间不容易协调。

迪米特法则是OOD的一个设计指引,如何正确、恰当的使用,取决于你的经验和悟性,你懂我意思吧?

你可能感兴趣的:(面向对象设计(OOD):迪米特法则(LoD))