迪米特法则,又叫做最少知识原则(Least Knowledge Principle):如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。


与改造前相比,Someone与Stranger之间的联系已经没有了,Someone不需要知道Stranger的存在就可以做同样的事情。代码如下:

迪米特法则,其根本思想,是强调了类之间的松耦合。
迪米特法则,另外几种表述方式:
只与你直接的朋友们通信(only talk to your immediate friends)
不要与“陌生人”说话(do not talk to strangers)
每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
以下的条件成为“朋友”条件:
当前对象本身(this)
以参量形式传入到当前对象中的方法
当前对象的实例变量直接引用的对象
当前对象的实例变量如果是一个聚集,那么聚集中的元素也都是朋友
当前对象所创建的对象
如果满足上面条件之一,就是当前对象的“朋友”,负责就是“陌生人”
下面从代码重构的角度讨论怎样将一个不符合迪米特法则的系统,重构成为复合迪米特法则的系统。
系统中有3个类,Someone,Friend,Stranger,其中Someone与Friend是朋友,Friend与Stranger是朋友,系统结构图如下:其中Friend持有Stranger的引用,所以是朋友,在代码中可以看到Someone接受Friend作为参量,因此二者是朋友。

public class ASomeone {
public void operation1(AFriend friend){
System.out.println("通过Someone来调用Stranger");
AStranger stranger = friend.provide();
stranger.operation3();
}
public static void main(String[] args) {
new ASomeone().operation1(new AFriend());
}
}
public class AFriend {
private AStranger stranger = new AStranger();
public AStranger provide(){
return stranger;
}
public void operation2(){
}
}
public class AStranger {
public void operation3(){
System.out.println("调用了陌生人的函数");
}
}
运行结果:通过Someone来调用Stranger
调用了陌生人的函数
显然Someone的方法operation1方法不满足迪米特法则,因为这个方法引用了Stranger对象,而Stranger对象不是Someone的朋友。
改造之后的结构图:

public class CSomeone {
public void operation1(CFriend cfriend){
cfriend.forward();
}
public static void main(String[] args) {
new CSomeone().operation1(new CFriend());
}
}
public class CFriend {
private CStranger cstranger = new CStranger();
public void operation2(){
}
public void forward(){
System.out.println("通过Friend来调用Stranger");
cstranger.operation3();
}
}
public class CStranger {
public void operation3(){
System.out.println("调用了陌生人的函数");
}
}
运行结果:通过Friend来调用Stranger
调用了陌生人的函数
由于原来Friend类的forward方法所做的事情就是以前Someone要做的事情,使用了Stranger的operation3方法,而这种forward方法叫做转发方法。
由于使用了调用转发,使得调用的细节被隐藏在Friend内部,从而使得Someone与Stranger之间的直接联系被省略掉了。这样一来,使得系统内部的耦合度降低,在系统的某个类需要被修改时,仅仅会直接影响到这个类的“朋友”们,不会直接影响其余部分。
与依赖反转法则相辅助,引进一个抽象的AbstractStranger角色,让Someone依赖于这个角色,从而是Someone与Stranger的具体实现脱耦。如下图:

public abstract class AbstractStranger {
public void operation3(){};
}
public class ASomeone {
public void operation1(AFriend friend){
System.out.println("通过Someone来调用Stranger");
AStranger stranger = friend.provide();
stranger.operation3();
}
public static void main(String[] args) {
new ASomeone().operation1(new AFriend());
}
}public class AFriend {
private AStranger stranger = new AStranger();
public AStranger provide(){
return stranger;
}
public void operation2(){
}
}public class AStranger {
public void operation3(){
System.out.println("调用了陌生人的函数");
}
}
运行结果:通过Someone来调用Stranger
调用了陌生人的函数