六大设计原则之五:迪米特法则
迪米特法则(Law of Demeter, LoD)是1987年秋天由lan holland在美国东北大学一个叫做迪米特的项目设计提出的,它要求 一个对象应该对其他对象有最少的了解 ,所以迪米特法则又叫做最少知识原则(Least Knowledge Principle, LKP)。 迪米特法则的意义在于降低类之间的耦合 。由于每个对象尽量减少对其他对象的了解,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。 值得一提的是,这一法则却不仅仅局限于计算机领域,在其他领域也同样适用。比如,美国人就在航天系统的设计中采用这一法则。 那么在实践中如何做到 一个对象应该对其他对象有最少的了解 呢?如果我们把一个对象看作是一个人,那么要实现“一个人应该对其他人有最少的了解”,做到两点就足够了:1.只和直接的朋友交流;2.减少对朋友的了解。下面就详细说说如何做到这两点。 迪米特法则还有一个英文解释是: talk only to your immediate friends(只和直接的朋友交流) 。什么是朋友呢?每个对象都必然会与其他的对象有耦合关系,两个对象之间的耦合就会成为朋友关系。那么什么又是直接的朋友呢? 出现在成员变量、方法的输入输出参数中的类就是直接的朋友 。迪米特法则要求只和直接的朋友通信。 我们举一个例子说明什么是朋友,什么是直接的朋友。很简单的例子:老师让班长清点全班同学的人数。这个例子中总共有三个类:老师 Teacher 、班长 GroupLeader 和学生 Student 。 老师类: 班长类: 学生类: 使用场景也是非常的简单: 在这个例子中,我们的 Teacher 有几个朋友?两个,一个是 GroupLeader ,因为它是 Teacher 的 command: 方法的输入参数;另一个是 Student ,因为在 Teacher 的 command: 方法体中使用了 Student 。 那么我们的 Teacher 有几个是直接的朋友?按照直接的朋友的定义“出现在成员变量、方法的输入输出参数中的类就是直接的朋友”,只有 GroupLeader 是 Teacher 的直接的朋友。 Teacher 在 command 方法中创建了 Student 的数组,和非直接的朋友 Student 发生了交流,所以,上述例子违反了迪米特法则。方法是类的一个行为,类竟然不知道自己的行为与其他的类产生了依赖关系,这是不允许的,严重违反了迪米特法则! 为了使上述例子符合迪米特法则,我们可以做如下修改: 修改后的GroupLeader: 修改后的老师类: 修改后的使用场景: 这样修改后,每个类都只和直接的朋友交流,有效减少了类之间的耦合。 如何减少对朋友的了解?如果你的朋友是个话痨加大喇叭,那就算你不主动去问他,他也会在你面前叨叨叨,把他所有的经历都讲给你听。所以,要减少对朋友的了解,请换一个内敛一点的朋友吧~换作在一个类中,就是 尽量减少一个类对外暴露的方法 。 举一个简单的例子说明一个类暴露方法过多的情况。这个例子描述的是一个人用咖啡机煮咖啡的过程,例子中只有两个类,一个是人,一个是咖啡机。 首先是咖啡机类 CoffeeMachine ,咖啡机制作咖啡只需要三个方法:1.加咖啡豆;2.加水;3.制作咖啡: 然后就是人类 Man ,该类只有一个方法 makeCoffee ,在该方法中使用咖啡机制作咖啡: 使用场景也非常的简单: 在这个例子中, CoffeeMachine 是 Man 的直接好友,但问题是 Man 对 CoffeeMachine 了解的太多了,其实人根本不关心咖啡机具体制作咖啡的过程。所以我们可以作如下优化: 优化后的咖啡机类,只暴露一个 work 方法,把制作咖啡的三个具体的方法 addCoffeeBean 、 addWater 、 makeCoffee 设为私有: 现在 Man 对 CoffeeMachine 的了解只有一个 work 方法了,所以 Man 类应该修改为: 这样修改后,通过减少 CoffeeMachine 对外暴露的方法,减少 Man 对 CoffeeMachine 的了解,从而降低了它们之间的耦合。 在实践中,只要做到 只和直接的朋友交流 和 减少对朋友的了解 ,就能满足迪米特法则。因此我们不难想象,迪米特法则的目的,是把我们的类变成一个个“肥宅”。“肥”在于一个类对外暴露的方法可能很少,但是它内部的实现可能非常复杂(这个解释有点牵强~)。“宅”在于它只和直接的朋友交流。在现实生活中“肥宅”是个贬义词,在日本“肥宅”已经成为社会问题。但是在程序中,一个“肥宅”的类却是优秀类的典范。 迪米特法则的核心观念就是类间解耦,弱耦合。只有弱耦合了之后,类的复用才可以提高,类变更的风险才可以减低。但解耦是有限度的,除非是计算机的最小单元--二进制的0和1,否则都是存在耦合的。所以在实际项目中,需要适度地参考这个原则,避免过犹不及。
六大设计原则之迪米特法则
1987年秋天,迪米特法则由美国Northeastern University的Ian Holland提出,被UML的创始者之一Booch等人普及。后来,因为经典著作The Pragmatic Programmer而广为人知。 迪米特法则 (Law of Demeter,LoD)又称为 最少知识原则 (Least KnowledgePrinciple,LKP),是指一个对象类对于其他对象类来说,知道得越少越好。也就是说,两个类之间不要有过多的耦合关系,保持最少关联性。 迪米特法则有一句经典语录:只和朋友通信,不和陌生人说话。也就是说,有 内在关联的类要内聚,没有直接关系的类要低耦合 。 就像家里的水管装修,有洗衣机地漏、卫生间地漏、厨房地漏,但它们最终都汇到同一个污水处理系统里。在平常使用时,我们不会考虑这些水管是怎么关联流向的,只需要考虑最上层的使用即可。 设计模式中的门面模式(Facade)和中介模式(Mediator),都是迪米特法则应用的例子 迪米特法则要求限制软件实体之间通信的宽度和深度,正确使用迪米特法则将有以下两个优点。 从迪米特法则的定义和特点可知,它强调以下两点: 广义的迪米特法则在类的设计上的体现: 这里用模拟学生、老师、校长之间关系的例子来说明迪米特法则来举例: 老师需要负责具体某一个学生的学习情况,而校长会关心老师所在班级的总体成绩。 违背原则的方案: 学生类: 老师类: 校长类: 校长想知道一个班级的总分和平均分,是应该找老师要,还是跟每一个学生要再进行统计呢?显然是应该找具体的班主任老师。我们在实际开发时,容易忽略这样的真实情况 迪米特法则改造方案: 老师类 校长类: 校长类直接调用老师类的接口,并获取相应的信息。这样一来,整个功能逻辑就非常清晰了。 在运用迪米特法则时要注意以下 6 点 缺点 迪米特法则是一种面向对象系统设计风格的一种法则,尤其适合做大型复杂系统设计指导原则。但是也会造成系统的不同模块之间的通信效率降低,使系统的不同模块之间不容易协调等缺点。 同时,因为迪米特法则要求类与类之间尽量不直接通信,如果类之间需要通信就通过第三方转发的方式,这就直接导致了 系统中存在大量的中介类 ,这些类存在的唯一原因是为了传递类与类之间的相互调用关系,这就毫无疑问的增加了系统的复杂度。解决这个问题的方式是: 使用依赖倒转原则,这样就可以使调用方和被调用方之间有了一个抽象层,被调用方在遵循抽象层的前提下就可以自由的变化,此时抽象层成了调用方的朋友。