迪米特法则

一,定义

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

通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。迪米特法则还有一个更简单的定义:只与直接的朋友通信。首先来解释一下什么是直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖关联组合聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。

二,实例

举一个例子:有一个集团公司,下属单位有分公司和直属部门,现在要求打印出所有下属单位的员工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的方法,总公司直接调用来打印,从而避免了与分公司的员工发生耦合。

三,总结

迪米特法则其根本思想是强调了类之间的松耦合,类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。

但是凡事都有度,虽然可以避免与非直接的类通信,但是要通信,必然会通过一个“中介”来发生联系,例如本例中,总公司就是通过分公司这个“中介”来与分公司的员工发生联系的。过分的使用迪米特原则,会产生大量这样的中介和传递类,导致系统复杂度变大。所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合。

参考:《大话设计模式》 http://blog.csdn.net/zhengzhb/article/details/7296930

源码:https://github.com/wangxp423/ExerciseDesignmodel

设计模式六大原则:
单一职责原则
开放-封闭原则
里氏替换原则
依赖倒置原则
接口隔离原则
迪米特法则

已标记关键词 清除标记
1) 优秀的程序应该是这样的:阅读时,感觉很优雅;新增功能时,感觉很轻松;运行时,感觉很快速,这就需要设计模式支撑。<br /> <br /> 2) 设计模式包含了大量的编程思想,讲授和真正掌握并不容易,网上的设计模式课程不少,大多讲解的比较晦涩,没有真实的应用场景和框架源码支撑,学习后,只知其形,不知其神。就会造成这样结果: 知道各种设计模式,但是不知道怎么使用到真实项目。本课程针对上述问题,有针对性的进行了升级 (1) 授课方式采用 图解+框架源码分析的方式,让课程生动有趣好理解 (2) 系统全面的讲解了设计模式,包括 设计模式七大原则、UML类图-类的六大关系、23种设计模式及其分类,比如 单例模式的8种实现方式、工厂模式的3种实现方式、适配器模式的3种实现、代理模式的3种方式、深拷贝等<br /> <br /> 3) 如果你想写出规范、漂亮的程序,就花时间来学习下设计模式吧<br /> <br /> 课程内容和目标<br /> <br /> 本课程是使用Java来讲解设计模式,考虑到设计模式比较抽象,授课采用 图解+框架源码分析的方式<br /> <br /> 1) 内容包括: 设计模式七大原则(单一职责、接口隔离、依赖倒转、里氏替换、开闭原则、迪米特法则、合成复用)、UML类图(类的依赖、泛化和实现、类的关联、聚合和组合) 23种设计模式包括:创建型模式:单例模式(8种实现)、抽象工厂模式、原型模式、建造者模式、工厂模式。结构型模式:适配器模式(3种实现)、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式(3种实现)。行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)<br /> <br /> 2) 学习目标:通过学习,学员能掌握主流设计模式,规范编程风格,提高优化程序结构和效率的能力。<br /> <div> <br /> </div>
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页