设计模式系列:迪米特法则
来源:互联网 发布:微信小程序读写数据库 编辑:程序博客网 时间:2024/05/16 15:33
问题由来
问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
解决方案:尽量降低类与类之间的耦合。
自从我们接触编程开始,就知道了软件编程的总的原则:低耦合,高内聚。无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率。低耦合的优点不言而喻,但是怎么样编程才能做到低耦合呢?那正是迪米特法则要去完成的。
定义
一个软件实体应当尽可能少的与其他实体发生相互作用。一个对象应该对其他对象有最少的了解。通俗的讲,一个类应该对自己需要耦合调用的类知道得最少,你(被耦合或调用的类)的内部是如何复杂都和我没关系,那是你的事情,我就知道你提供的这么多public方法,我就调用这么多,其他的我一概不关心。即:一个对象对其他对象的引用应该降到最低。
迪米特法则对类的低耦合做了明确的要求,其包含以下4层含义:
只和朋友交流
朋友类的定义是这样的,出现在成员变量、方法的输入输出参数中的类成为成员朋友类,如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友。而出现在方法内部的类不属于朋友类。朋友间也是有距离的
一个类公开的public属性或方法越多,修改时涉及的面也就越大,变更引起的风险扩散也就越大。因此,为了保持朋友类间的距离,在设计时需要反复衡量:是否可以再减少public方法和属性,是否可以修改为private、protected等访问权限,是否可以加上final关键字等。是自己的就是自己的
在实际应用中经常会出现这样的一个方法:放在本类中也可以,放在其他类中也没有错,那怎么去衡量呢?你可以坚持这样一个原则:如果一个方法放在本类中,既不增加类间关系,也不对本类产生负面影响,就放置在本类中。谨慎使用serializable
RMI中注意
最佳实践
迪米特法则的核心观念就是:类间解耦、弱耦合,只有弱耦合了,类的复用性才可以提高,其要求的结果就是产生了大量的中转或跳转类,导致系统的复杂性提高,同时也为维护带来了难度。我们在使用时要反复权衡,既做到结构清晰,又做到高内聚低耦合。另外解耦是有限度的,需要适当的考虑这个原则。防止过犹不及。
例子
举一个例子:有一个集团公司,下属单位有分公司和直属部门,现在要求打印出所有下属单位的员工ID。先来看一下违反迪米特法则的设计。
//总公司员工 class Employee{ private String id; public void setId(String id){ this.id = id; } public String getId(){ return id; } } //分公司员工 class SubEmployee{ private String id; public void setId(String id){ this.id = id; } public String getId(){ return id; } } class SubCompanyManager{ public List<SubEmployee> getAllEmployee(){ List<SubEmployee> list = new ArrayList<SubEmployee>(); for(int i=0; i<100; i++){ SubEmployee emp = new SubEmployee(); //为分公司人员按顺序分配一个ID emp.setId("分公司"+i); list.add(emp); } return list; } } class CompanyManager{ public List<Employee> getAllEmployee(){ List<Employee> list = new ArrayList<Employee>(); for(int i=0; i<30; i++){ Employee emp = new Employee(); //为总公司人员按顺序分配一个ID emp.setId("总公司"+i); list.add(emp); } return list; } public void printAllEmployee(SubCompanyManager sub){ List<SubEmployee> list1 = sub.getAllEmployee(); for(SubEmployee e:list1){ System.out.println(e.getId()); } List<Employee> list2 = this.getAllEmployee(); for(Employee e:list2){ System.out.println(e.getId()); } } } public class Client{ public static void main(String[] args){ CompanyManager e = new CompanyManager(); e.printAllEmployee(new SubCompanyManager()); } }
现在这个设计的主要问题出在CompanyManager中,根据迪米特法则,只与直接的朋友发生通信,而SubEmployee类并不是CompanyManager类的直接朋友(以局部变量出现的耦合不属于直接朋友),从逻辑上讲总公司只与他的分公司耦合就行了,与分公司的员工并没有任何联系,这样设计显然是增加了不必要的耦合。按照迪米特法则,应该避免类中出现这样非直接朋友关系的耦合。修改后的代码如下:
class SubCompanyManager{ public List<SubEmployee> getAllEmployee(){ List<SubEmployee> list = new ArrayList<SubEmployee>(); for(int i=0; i<100; i++){ SubEmployee emp = new SubEmployee(); //为分公司人员按顺序分配一个ID emp.setId("分公司"+i); list.add(emp); } return list; } public void printEmployee(){ List<SubEmployee> list = this.getAllEmployee(); for(SubEmployee e:list){ System.out.println(e.getId()); } } } class CompanyManager{ public List<Employee> getAllEmployee(){ List<Employee> list = new ArrayList<Employee>(); for(int i=0; i<30; i++){ Employee emp = new Employee(); //为总公司人员按顺序分配一个ID emp.setId("总公司"+i); list.add(emp); } return list; } public void printAllEmployee(SubCompanyManager sub){ sub.printEmployee(); List<Employee> list2 = this.getAllEmployee(); for(Employee e:list2){ System.out.println(e.getId()); } } }
修改后,为分公司增加了打印人员ID的方法,总公司直接调用来打印,从而避免了与分公司的员工发生耦合。
迪米特法则的初衷是降低类之间的耦合,由于每个类都减少了不必要的依赖,因此的确可以降低耦合关系。但是凡事都有度,虽然可以避免与非直接的类通信,但是要通信,必然会通过一个“中介”来发生联系,例如本例中,总公司就是通过分公司这个“中介”来与分公司的员工发生联系的。过分的使用迪米特原则,会产生大量这样的中介和传递类,导致系统复杂度变大。所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合
- 设计模式系列:迪米特法则
- 【设计模式】迪米特法则
- 设计模式:迪米特法则
- 设计模式 迪米特法则
- 设计模式--迪米特法则
- 【设计模式】迪米特法则
- 设计模式---迪米特法则
- 设计模式-迪米特法则
- 设计模式【迪米特法则】
- 设计模式系列课程07之【迪米特法则】
- 设计模式系列(4)迪米特法则形象解释
- 设计模式 --6大法则 --迪米特法则
- 设计模式之 迪米特法则
- 设计模式之迪米特法则
- 设计模式: 11 迪米特法则
- 设计模式之迪米特法则
- 设计模式之迪米特法则
- 迪米特法则(设计模式_13)
- 设计模式系列:接口隔离原则
- iOS CGRectInset
- 【lightoj】-1294 Positive Negative Sign
- WebGL中纹理贴图过滤器(filter)参数设置详解
- android /system/vold源码分析(2)
- 设计模式系列:迪米特法则
- zigbee基础应用(六)温湿度传感器DHT11
- 在串口通信开发中实现自动查找串口端口的方法
- 设计模式系列:合成复用原则
- 如何辨别数清冲突域和广播域
- Excel文件导出为Word文档
- 蓝桥杯 李白打酒-递归
- tableview旋转90度不能对齐
- Java三种判断字母大小写的方法