5.迪米特法则(Low of Demeter)
迪米特法则又叫:最少知识原则(Least Knowledge Principle) ,简称LKP
迪米特原则要求类要小气一点,类只和自己的朋友交流,不和陌生人说话。
朋友的定义:
迪米特法则的定义:两个类如果不必彼此直接通信,那么这两个类就不应该发生相互作用,如果其中一个类需要调用另一个类的某一个方法的,可以通过第三方转发这个调用。
**只和朋友交流**
举例说明:
在大学中,有很多的院系,每个院系都有院长,辅导员和学生,院长只和辅导员打交道,而辅导员和学生打交道。因此院长和学生就是陌生人的关系。
假设院长要找几个学生干活,但是学生只听辅导员的,因为他不认识院长。
设计类:
public class Student { public void work() { System.out.println("学生干活"); } } public class Counsellor { private Student student; public void makeStudentWork() { this.student.work(); } public Student getStudent() { return student; } public void setStudent(Student student) { this.student = student; } }
首先我们看如果不使用迪米特原则,那么院长如果找学生干活的话:
public class President { public void makeCounsellorWork() { Student student = new Student(); this.counsellor.setStudent(student); this.counsellor.makeStudentWork(); } public Counsellor getCounsellor() { return counsellor; } public void setCounsellor(Counsellor counsellor) { this.counsellor = counsellor; } }
因为学生不认识院长,只认识辅导员,因此院长首先要找到一个干活的学生,然后还要找到这个学生的辅导员,然后让这个辅导员指挥学生干活:
public class Traditional { public static void main(String[] args) { President president = new President(); Counsellor counsellor = new Counsellor(); president.setCounsellor(counsellor); president.makeCounsellorWork(); } }
院长和学生是陌生人,但是在方法内却依赖了学生这个类,这不符合迪米特法则。我们想一下, 如果院长找学生干活的话,那么他应该直接找辅导员,说:给我找两个学生来干个活。
找学生的事应该辅导员来做,而不是院长找学生。因此我们的方法,应该把找学生这个交给辅导员去做。
public class Counsellor { private Student student; public void makeStudentWork() { this.student = new Student(); this.student.work(); } public Student getStudent() { return student; } public void setStudent(Student student) { this.student = student; } }
院长只需要告诉辅导员找个学生干活:
public void makeCounsellorWork() { this.counsellor.makeStudentWork(); }
至于辅导员怎么找学生,跟院长没有关系,当学生的方法属性等发生改变时,只需要更改辅导员类,而不需要修改院长这个类。
**尽量降低一个类的访问权限, 减少与朋友的交流**
迪米特法则要求类要小气一点,尽量建少与朋友的交流,也就是尽量少的提供public 方法,转而多使用private, default, protected等方法,尽量使类可以独立的完成自己的任务。
我们想象一下装软件的过程,在装软件的页面,根据我们的选择,点击下一步跳转不同的页面。我们来实现这个调用:
/** * 假设一个软件,共有四个步骤: * 执行流程,当进入安装页面首先调用第一个方法, * 然后根据第一个方法的返回值决定调用第二个或者第三个方法。如果调用第二个方法则安装结束,如果调用第三个方法则根据返回结果决定是否调用第四个方法 * 并结束安装。 * @author ZhaoShuai * @date Create in 2020/4/17 **/ public class App { public int first() { System.out.println("开始安装,进行第一步"); return new Random().nextInt(4); } public void second() { System.out.println("调用结束安装方法"); } public int third() { System.out.println("调用第三个方法"); return new Random().nextInt(3); } public void four() { System.out.println("调用第四个方法"); } } public class Client { public static void main(String[] args) { App app = new App(); int first = app.first(); while (first == 1 || first == 0) { first = app.first(); } System.out.println("第一步返回结果:" + first); if (first == 2) { app.second(); } else if (first == 3) { System.out.println("安装进行第二步"); int third = app.third(); System.out.println("第二步返回结果" + third); if (third == 2) { System.out.println("进行安装第三步"); app.four(); app.second(); } } } }
方法很简单,我们会发现app类内部的方法,都是public的,而且会按照固定的模式去执行,而这个执行过程交给Client类来管理。也就是让客户端来决定下一步如何调用。
这种设计中,客户端调用大量的app方法,就会使客户端与app两个类的耦合度过高。这时无论修改app内哪儿个方法的返回值,都需要修改客户端的调用代码返回值。
根据迪米特法则,我们可以把这个调用过程放进app类里面:
public class App2 { public void startRun() { int first = this.first(); while (first == 1 || first == 0) { first = this.first(); } System.out.println("第一步返回结果:" + first); if (first == 2) { this.second(); } else if (first == 3) { System.out.println("安装进行第二步"); int third = this.third(); System.out.println("第二步返回结果" + third); if (third == 2) { System.out.println("进行安装第三步"); this.four(); this.second(); } } } private int first() { System.out.println("开始安装,进行第一步"); return new Random().nextInt(4); } private void second() { System.out.println("调用结束安装方法"); } private int third() { System.out.println("调用第三个方法"); return new Random().nextInt(3); } private void four() { System.out.println("调用第四个方法"); } } public class Client2 { public static void main(String[] args) { App2 app2 = new App2(); app2.startRun(); } }
这样设计的意思就是:你已经是一个成熟的软件了,应该可以自己执行安装过程,而客户端只需要点击开始安装按钮,剩下的安装过程全都交给程序内部自己执行,这样设计
无论app2类内部的方法如何改变,我们都只需要在类内部更改,与外部调用无关。这样就做到了解耦。根据迪米特法则,如果我们确定客户端与app类在同一个包下,由客户端来
调用app2的安装,那么app2的类应该设计为包访问权限,即: class App2{...}
设计原则:
迪米特法则的缺陷:
迪米特法则要求降低类之间的耦合关系,如果要调用尽量通过第三方调用,但是这样就会导致产生大量的中间第三方类,这个类里的大量方法仅仅只是转发类的调用,没有其他实际意义。这样就会导致类的复杂性增加。
原文:https://www.cnblogs.com/Zs-book1/p/12718047.html