面向对象六大原则——迪米特法则

什么是迪米特法则(Law of Demeter, LoD)

 迪米特法则也可以称为最少知识法则(Least Knowledge Principle, LKP)。它们都描述了一个规则:一个对象应该对其他对象有最少的了解。通俗来说,一个类应该对自己需要耦合或调用的类知道最少,也就是对于被依赖的类,向外公开的方法应该尽可能的少。

 迪米特法则还有一种解释:Only talk to your immediate friends,只与直接朋友进行通信。关于朋友给出如下解释:两个对象之间的耦合关系称之为朋友,通常有依赖,关联,聚合,组成等。而直接朋友通常表现为关联,聚合和组成关系,即两个对象之间联系更为紧密,通常以成员变量,方法参数和返回值的形式出现。

LoD实例演示

 迪米特法则强调了下面两点:

  • 从被依赖者的角度:只暴露应该暴露的方法或属性,即编写相关的类时确定方法和属性的权限
  • 从依赖者的角度来看,只依赖应该依赖的对象

先举例演示第一点:当我们按下计算机的按钮的时候,计算机会指行一系列操作:保存当前任务,关闭相关服务,接着关闭显示屏,最后关闭电源,这些操作完成则计算机才算关闭。如下是代码示例:

//计算机类
public class Computer{

    public void saveCurrentTask(){
        //do something
    }
    public void closeService(){
        //do something
    }
    public void closeScreen(){
        //do something
    }

    public void closePower(){
        //do something
    }

    public void close(){
        saveCurrentTask();
        closeService();
        closeScreen();
        closePower();
    }
}

//人
public class Person{
    private Computer c;

    ...

    public void clickCloseButton(){
      //现在你要开始关闭计算机了,正常来说你只需要调用close()方法即可,
      //但是你发现Computer所有的方法都是公开的,该怎么关闭呢?于是你写下了以下关闭的流程:        
        c.saveCurrentTask();
        c.closePower();
        c.close();

        //亦或是以下的操作        
        c.closePower();

        //还可能是以下的操作
        c.close();
        c.closePower();
    }

}

 观察上面的代码我们发现了什么问题:对于人来说,我期待的结果只是按下关闭电钮然后计算机“啪”的给我关了,而不是需要我去小心的去保存当前正在执行的任务等等。在上面的代码中,c是一个完全暴露的对象,它的方法是完全公开的,对于Person来说,手里面就如同多出了好几把钥匙,至于具体用哪一把他不知道,所以只能一把一把的去试一遍,显然这样的设计是不对的。

 根据迪米特法则的第一点:从被依赖者的角度,只暴露应该暴露的方法。在本例中,应该暴露的方法就是close(),关于计算机的其他操作不是依赖者应该关注的问题,应该对依赖者关闭,重新设计如下:

//计算机类
public class Computer{

    private void saveCurrentTask(){
        //do something
    }
    private void closeService(){
        //do something
    }
    private void closeScreen(){
        //do something
    }

    private void closePower(){
        //do something
    }

    public void close(){
        saveCurrentTask();
        closeService();
        closeScreen();
        closePower();
    }
}

//人
public class Person{
    private Computer c;
    ...

    public  void clickCloseButton(){
       c.close();
    }

}

现在举例演示第二点:在我们生活中会有这样的情况,比如张三去找李四帮忙做一件事,对于李四来说这件事也很棘手,李四也做不了,但是李四有一个好哥们王五却能完成这件事,所以李四就把这件事交给王五去办(在本例中,张三和王五是不认识的)。现在我们暂定张三为A,李四为B,王五为C,代码示例如下:

//张三找李四办事
public class A {
	public String name;
	public A(String name) {
		this.name = name;
	}
	public B getB(String name) {
		return new B(name);
	}
	public void work() {
		B b = getB("李四");
		C c = b.getC("王五");
		c.work();
	}
}

//李四办不了于是去找王五
public class B {
	private String name;
	public B(String name) {
		this.name = name;
	}
	public C getC(String name) {
		return new C(name);
	}
}

//对于王五来说so easy,办得妥妥的
public class C {
	public String name;
	public C(String name) {
		this.name = name;
	}
	public void work() {
		System.out.println(name + "把这件事做好了");
	}
}

public class Client {
	public static void main(String[] args) {
		A a = new A("张三");
		a.work();
	}
}
结果:王五把事情做好了

 上面的设计输出答案是正确的,王五确实把事情办妥了。但是我们仔细看业务逻辑确发现这样做事不对的。张三和王五互相不认识,那为什么代表张三的A类中会有代表李四的C类呢?这样明显是违背了迪米特法则的。现在我们对上面的代码进行重构,根据迪米特法则的第二点:从依赖者的角度来看,只依赖应该依赖的对象。在本例中,张三只认识李四,那么只能依赖李四。重构后代码如下:

//张三认识李四,只依赖李四
public class A {
	public String name;
	public A(String name) {
		this.name = name;
	}
	public B getB(String name) {
		return new B(name);
	}
	public void work() {
		B b = getB("李四");
		b.work();
	}
}

//李四依赖王五
public class B {
	private String name;
	public B(String name) {
		this.name = name;
	}
	public C getC(String name) {
		return new C(name);
	}

	public void work(){
		C c = getC("王五");
		c.work();
	}
}

//王五把事情办得妥妥的
public class C {
	public String name;
	public C(String name) {
		this.name = name;
	}
	public void work() {
		System.out.println(name + "把这件事做好了");
	}
}

public class Client {
	public static void main(String[] args) {
		A a = new A("张三");
		a.work();
	}
}
结果:王五把事情做好了

总结

 迪米特法则的目的是让类之间解耦,降低耦合度,提高类的复用性。但是设计原则并非有利无弊,使用迪米特法则会产生大量的中转类或跳转类,导致系统复杂度提高。在实际的项目中,需要适度的考虑这个原则,不能因为套用原则而反而使项目设计变得复杂。

参考书籍与链接

  • 《设计模式之禅》
  • https://tianweili.github.io/2015/02/12/设计模式六大原则-迪米特法则/
  • https://blog.csdn.net/zhengzhb/article/details/7296930
  • https://www.jianshu.com/p/30931aab5ea0

你可能感兴趣的:(---------【设计模式】,◆【架构的艺术】)