当前位置:网站首页>迪米特法则
迪米特法则
2022-06-27 10:05:00 【华为云】
什么是迪米特法则
迪米特法则(Law of Demeter, LoD),又被称为最少知识原则,这个原则规定了,一个对象应该对另一个对象有最少的了解,什么又是最少的了解,就是减少一个对象在另一个对象出现的次数,甚至不出现,减少类于类之间的耦合关系。
一个类对另一个类的了解,都是基于其public方法。
迪米特法则还有一个英文解释:Only talk to your immediate friends,只于一个类之间的朋友进行交流。
什么是类于类之间的交流?无非就是一个类中的方法中调用另一个类的方法。
什么是直接朋友?一个类的朋友就是这个类本身、这个类的成员对象、这个对象创建的对象、当前对象的方法参数等等。
参考如下代码,Address,Book,Stuent这些都是Teacher的朋友。
public class Teacher { private Address address; public void tech(Book book){ System.out.println(book.getName); } public Studnet findStudent(){ return Student(); }}只和朋友交流
如何做到之和朋友类交流,来看一个案例:
老师想让班长去清点一下班级的人数,让我们用代码去实现这个场景;
先看类图:
代码:
public class Student {}public class Teacher { void command(Monitor monitor){ List<Student> listStudent = new ArrayList<>(); for (int i=0; i<3; i++){ listStudent.add(new Student()); } monitor.countStudent(listStudent); }}public class Monitor { void countStudent(List<Student> list){ System.out.println("学生人数:" + list.size()); }}public class Client { public static void main(String[] args) { Teacher teacher = new Teacher(); teacher.command(new Monitor()); }}运行结果:
运行结果很成功,学生人数被统计出来了。
但是这样的设计有什么问题?
首先Teacher类有几个朋友类,只有Monitor类(成员变量),那这里Student类是它的朋友类吗?不是,Student类是在方法中产生的,不是朋友类,但它却出现在了Teacher类中,这就相当于和Teacher类产生了交流,产生了依赖,这样回导致,如果以后Student类发生了改变,Teacher类也得同步参数修改,这是严重不允许的,严重违反迪米特法则。
让我们去修改一下这个类图结构:

public class Student {}public class Monitor { private List<Student> list; public Monitor(List<Student> list) { this.list = list; } void countStudent(){ System.out.println("学生人数:" + list.size()); }}public class Teacher { void command(Monitor monitor){ monitor.countStudent(); }}public class Client { public static void main(String[] args) { Teacher teacher = new Teacher(); List<Student> listStudent = new ArrayList<>(); for (int i=0; i<3; i++){ listStudent.add(new Student()); } teacher.command(new Monitor(listStudent)); }}观察改进前和改进后的代码有什么区别,改进前,Monitor类需要统计Student类,需要一个List,通过它的上级调用类,也就是Teacher类创建得到,虽然完成了业务,但是却导致Teacher类和它的非朋友类Student产生了交流,以后如果Student类有改动,Teacher类也会跟着改,于是进行修改,把Monitor类和Studnet类的依赖用成员变量的方式进行依赖,通过构造方法进行传递,这样Teacher类就可以不用和Studnet类进行交流,就能完成业务了。
朋友之间交流也不要太密切
迪米特法则中规定,一个类中,只与这个类的朋友进行联系,说简单点,就是一个类的方法中,如果一个类不是这个类的成员变量、函数参数、或者这个类通过方法创建出来的,最好不要出现在这个方法中。
但是,即使这个某个类是这个类的朋友,也应该尽可能的减少交流,也就是调用。
比如说,我们的电脑要安装一个软件,是不是要点击软件包,然后一直点下一步,如果某一步失败,后续的步骤也不能继续往下执行了。
来用代码表示是什么样的?
public class Install { int checkDir(){ System.out.println("检查目录"); return 1; } int checkSpace(){ System.out.println("检查空间"); return 1; } int install(){ System.out.println("安装软件"); return 1; }}public class Computer { private Install install; public Computer(Install install) { this.install = install; } void installSoftWare(){ //检查目录是否存在 int i = install.checkDir(); if (i==1){ //检查空间是否足够 int i1 = install.checkSpace(); if (i1==1){ int install = this.install.install(); if (install==1){ System.out.println("安装成功"); return; }else { System.out.println("安装失败"); return; } } } System.out.println("安装失败"); }}仔细看Computer类安装的方法,它和之间的朋友类Install进行交流,每次步骤返回1,代表成功,就进行下一步。这样的代码也许能模拟这个业务,但是它有什么问题?我们得考虑以后代码变动的风险,如果以后,每个安装步骤的返回值,不在返回1代表成功,而是布尔类型的true代表成功,这样回导致Computer类所有对这些方法调用的地方都得修改。
为了改进这种情况,我们需要对类结构进行修改,如下:
public class Install { private int checkDir(){ System.out.println("检查目录"); return 1; } private int checkSpace(){ System.out.println("检查空间"); return 1; } private int install(){ System.out.println("安装软件"); return 1; } public void installSoftForComputer(){ int i = checkDir(); if (i==1){ //检查空间是否足够 int i1 = checkSpace(); if (i1==1){ int install = install(); if (install==1){ System.out.println("安装成功"); return; }else { System.out.println("安装失败"); return; } } } System.out.println("安装失败"); }}public class Computer { private Install install; public Computer(Install install) { this.install = install; } void installSoftWare(){ //检查目录是否存在 install.installSoftForComputer(); }}看到改变前后的区别了吗?我把之前computer需要一个一个去调用的方法,封装在了Install一个public方法中,并且把每个安装步骤都设置为私有,这样有什么好处?我们减少了类与类之间的交流,同时也减少了它们变更带了的风险,以后Install类的变更,比如变更返回类型,那也只对Install内部有影响,这就是我们常说的高内聚!
边栏推荐
- 导师邀请你继续跟他读博,你会不会立马答应?
- Quartz (timer)
- 【报名】基础架构设计:从架构热点问题到行业变迁 | TF63
- torch. utils. data. Randomsampler and torch utils. data. Differences between sequentialsampler
- R语言使用caret包的preProcess函数进行数据预处理:对所有的数据列进行center中心化(每个数据列减去平均值)、设置method参数为center
- R语言plotly可视化:plotly可视化基础小提琴图(basic violin plot in R with plotly)
- JS 客户端存储
- 【系统设计】邻近服务
- Scientists develop two new methods to provide stronger security protection for intelligent devices
- torch.utils.data.RandomSampler和torch.utils.data.SequentialSampler的区别
猜你喜欢

Easy to understand Laplace smoothing of naive Bayesian classification

三层架构中,数据库的设计在哪一层实现,不是在数据存储层吗?

lvi-sam 总结

感应电机直接转矩控制系统的设计与仿真(运动控制matlab/simulink)

通俗易懂理解朴素贝叶斯分类的拉普拉斯平滑

mysql数据库汉字模糊查询出现异常
测试同学怎么参与codereview

Oracle连接MySQL报错IM002

【系统设计】邻近服务

QT运行显示 This application failed to start because it could not find or load the Qt platform plugin
随机推荐
R language plot visualization: visualize the normalized histograms of multiple data sets, add density curve KDE to the histograms, set different histograms to use different bin sizes, and add edge whi
Record in detail the implementation of yolact instance segmentation ncnn
导师邀请你继续跟他读博,你会不会立马答应?
Unity - - newtonsoft. Analyse json
【STM32】HAL库 STM32CubeMX教程十二—IIC(读取AT24C02 )
js 所有的网络请求方式
C语言学习-Day_04
文件名设置导致writelines写入报错:OSError: [Errno 22] Invalid argument
QT运行显示 This application failed to start because it could not find or load the Qt platform plugin
Vector:: data() pointer usage details
上周热点回顾(6.20-6.26)
6月23日《Rust唠嗑室》第三期B站视频地址
邮件系统(基于SMTP协议和POP3协议-C语言实现)
C language learning day_ 05
Explain the imaging principle of various optical instruments in detail
Google browser chropath plug-in
R langage plotly visualisation: visualisation de plusieurs histogrammes normalisés d'ensembles de données et ajout d'une courbe de densité KDE à l'histogramme, réglage de différents histogrammes en ut
细说物体检测中的Anchors
openpyxl表格读取实例
Multi thread implementation rewrites run (), how to inject and use mapper file to operate database