转贴: 设计模式六大原则(5):迪米特法则

 
原帖子的后续评论里面很多值得仔细去看 切记!像21楼
21楼 chenshufei2 2012-09-23 12:47发表 [回复]
上个例子,就是方法的界定。通常从现实中可以抽取多个对象名词,又有多个动作方法。到底这些动作应该是哪个对象的,我个人觉得,要看动作操作的数据是谁的,那谁就应该负责提供方法。
像上面的打印子公司的员工ID,只有子公司自己才知道他的员工ID,所以打印子公司的ID,理应由子公司处理。

 
分类: 设计模式 2012-02-27 08:40 18855人阅读 评论(35) 收藏 举报
定义:一个对象应该对其他对象保持最少的了解。

问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。

解决方案:尽量降低类与类之间的耦合。

自从我们接触编程开始,就知道了软件编程的总的原则:低耦合,高内聚。无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,才能提高 代码的复用率。低耦合的优点不言而喻,但是怎么样编程才能做到低耦合呢?那正是迪米特法则要去完成的。

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

举一个例子:有一个集团公司,下属单位有分公司和直属部门,现在要求打印出所有下属单位的员工ID。先来看一下违反迪米特法则的设计。

  1. //总公司员工
  2. class Employee{
  3. private String id;
  4. public void setId(String id){
  5. this.id = id;
  6. }
  7. public String getId(){
  8. return id;
  9. }
  10. }
  11. //分公司员工
  12. class SubEmployee{
  13. private String id;
  14. public void setId(String id){
  15. this.id = id;
  16. }
  17. public String getId(){
  18. return id;
  19. }
  20. }
  21. class SubCompanyManager{
  22. public List<SubEmployee> getAllEmployee(){
  23. List<SubEmployee> list = new ArrayList<SubEmployee>();
  24. for(int i=0; i<100; i++){
  25. SubEmployee emp = new SubEmployee();
  26. //为分公司人员按顺序分配一个ID
  27. emp.setId("分公司"+i);
  28. list.add(emp);
  29. }
  30. return list;
  31. }
  32. }
  33. class CompanyManager{
  34. public List<Employee> getAllEmployee(){
  35. List<Employee> list = new ArrayList<Employee>();
  36. for(int i=0; i<30; i++){
  37. Employee emp = new Employee();
  38. //为总公司人员按顺序分配一个ID
  39. emp.setId("总公司"+i);
  40. list.add(emp);
  41. }
  42. return list;
  43. }
  44. public void printAllEmployee(SubCompanyManager sub){
  45. List<SubEmployee> list1 = sub.getAllEmployee();
  46. for(SubEmployee e:list1){
  47. System.out.println(e.getId());
  48. }
  49. List<Employee> list2 = this.getAllEmployee();
  50. for(Employee e:list2){
  51. System.out.println(e.getId());
  52. }
  53. }
  54. }
  55. public class Client{
  56. public static void main(String[] args){
  57. CompanyManager e = new CompanyManager();
  58. e.printAllEmployee(new SubCompanyManager());
  59. }
  60. }

现在这个设计的主要问题出在CompanyManager中,根据迪米特法则,只与直接的朋友发生通信,而SubEmployee类并不是 CompanyManager类的直接朋友(以局部变量出现的耦合不属于直接朋友),从逻辑上讲总公司只与他的分公司耦合就行了,与分公司的员工并没有任 何联系,这样设计显然是增加了不必要的耦合。按照迪米特法则,应该避免类中出现这样非直接朋友关系的耦合。

(我的注释:SubEmployee类并不是 CompanyManager类的直接朋友,而Employee却是CompanyManager的直接朋友,因为它是getAllEmployee的返回值)

修改后的代码如下:

  1. class SubCompanyManager{
  2. public List<SubEmployee> getAllEmployee(){
  3. List<SubEmployee> list = new ArrayList<SubEmployee>();
  4. for(int i=0; i<100; i++){
  5. SubEmployee emp = new SubEmployee();
  6. //为分公司人员按顺序分配一个ID
  7. emp.setId("分公司"+i);
  8. list.add(emp);
  9. }
  10. return list;
  11. }
  12. public void printEmployee(){
  13. List<SubEmployee> list = this.getAllEmployee();
  14. for(SubEmployee e:list){
  15. System.out.println(e.getId());
  16. }
  17. }
  18. }
  19. class CompanyManager{
  20. public List<Employee> getAllEmployee(){
  21. List<Employee> list = new ArrayList<Employee>();
  22. for(int i=0; i<30; i++){
  23. Employee emp = new Employee();
  24. //为总公司人员按顺序分配一个ID
  25. emp.setId("总公司"+i);
  26. list.add(emp);
  27. }
  28. return list;
  29. }
  30. public void printAllEmployee(SubCompanyManager sub){
  31. sub.printEmployee();
  32. List<Employee> list2 = this.getAllEmployee();
  33. for(Employee e:list2){
  34. System.out.println(e.getId());
  35. }
  36. }
  37. }

修改后,为分公司增加了打印人员ID的方法,总公司直接调用来打印,从而避免了与分公司的员工发生耦合。

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

更多

ZT 设计模式六大原则(5):迪米特法则的更多相关文章

  1. ZT 设计模式六大原则(6):开闭原则

    ZT 设计模式六大原则(6):开闭原则 分类: 设计模式 2012-02-27 08:48 24870人阅读 评论(72) 收藏 举报 设计模式扩展框架编程测试 定义:一个软件实体如类.模块和函数应该 ...

  2. ZT 设计模式六大原则(1):单一职责原则

    zt 设计模式六大原则(1):单一职责原则 分类: 设计模式 2012-02-21 09:52 25059人阅读 评论(65) 收藏 举报 设计模式stringclass编程 (THERE SHOUL ...

  3. zt 设计模式六大原则(3):依赖倒置原则

    下面说法对不对? 父类将算法(逻辑)封装起来,子类实现细节:这个就叫DIP(依赖倒置:Dependency Inversion Principles),模板模式就是这个原则的实现.如果在父类中加一个t ...

  4. ZT 设计模式六大原则(4):接口隔离原则

    设计模式六大原则(4):接口隔离原则 分类: 设计模式 2012-02-27 08:32 17948人阅读 评论(21) 收藏 举报 设计模式classinterfacecstring框架 定义:客户 ...

  5. ZT 设计模式六大原则(2):里氏替换原则

    设计模式六大原则(2):里氏替换原则 分类: 设计模式 2012-02-22 08:46 23330人阅读 评论(41) 收藏 举报 设计模式class扩展string编程2010 肯定有不少人跟我刚 ...

  6. GOF提出的23种设计模式是哪些 设计模式有创建形、行为形、结构形三种类别 常用的Javascript中常用设计模式的其中17种 详解设计模式六大原则

    20151218mark 延伸扩展: -设计模式在很多语言PHP.JAVA.C#.C++.JS等都有各自的使用,但原理是相同的,比如JS常用的Javascript设计模式 -详解设计模式六大原则 设计 ...

  7. PHP 设计模式六大原则

    http://www.cnblogs.com/yujon/p/5536118.html 设计模式六大原则(1):单一职责原则 不要存在多于一个导致类变更的原因.通俗的说,即一个类只负责一项职责 设计模 ...

  8. Java设计模式六大原则-2

    Java设计模式六大原则-2 做Java程序开发的每天都在使用JDK,Spring,SpringMvc,Mybatis,Netty,MINA等框架,但很少有人懂得背后的原理.即使打开跟下原码也是一头雾 ...

  9. 设计模式六大原则 All In one

    设计模式六大原则 All In one 开闭原则: 对扩展开放,对修改关闭; 设计模式的六大原则: 0.总原则-开闭原则 对扩展开放, 对修改封闭; 在程序需要进行拓展的时候, 不能去修改原有的代码, ...

随机推荐

  1. Tensorflow中的数据对象Dataset

    基础概念 在tensorflow的官方文档是这样介绍Dataset数据对象的: Dataset可以用来表示输入管道元素集合(张量的嵌套结构)和"逻辑计划"对这些元素的转换操作.在D ...

  2. 最小化安装的redhat/centos安装gnome桌面

    因系统版本和语言环境不同,安装包的名字会有所差别 安装方式可以选择直接联网安装,也可以加载dvd镜像源安装,这里针对配置redhat/centos本地dvd的yum源做个记录: 1.复制 redhat ...

  3. iostat命令——监控系统设备的IO负载情况

    iostat命令的安装 #yum install sysstat iostat常见选项 -t   输出数据时打印搜集数据的时间 -m  输出的数据以MB为单位 -d  显示磁盘的统计信息 # iost ...

  4. The Internet Communications Engine (Ice) 跨平台异构通讯方案 第一弹-ICE简介

    .net中的通讯方案很多,从.net Remoting,MSMQ,Webservice,WSE,WCF等等,他们都有一个特点,易用,但是都不能跨语种异构,如果你服务端要用java开发,客户端用C#开发 ...

  5. Javascript制作伸缩的二级菜单

    1.javascript方法 <style> #navigation { width: 200px; font-family: Arial; } #navigation > ul { ...

  6. Apache Commons Email 使用网易企业邮箱发送邮件

    最近使用HtmlEmail 发送邮件,使用网易企业邮箱,发送邮件,死活发不出去!原以为是网易企业邮箱,不支持发送邮箱,后面经过研究发现,是apache htmlEmail 的协议导致,apache E ...

  7. node.js之内存机制特性

    Node.JS的V8引擎具有垃圾回收机制与内存限制的特性,V8的内存限制:64位系统约为1.4GB.32位系统约为0.7GB:V8采用基于分代式垃圾回收机制,堆内存结构分为新生代和老生代,新生代达到一 ...

  8. Node.js开发——MongoDB与Mongoose

    为了保存网站的用户数据和业务数据,通常需要一个数据库.MongoDB和Node.js特别般配,因为MongoDB是基于文档的非关系型数据库,文档是按BSON(JSON的轻量化二进制格式)存储的,增删改 ...

  9. 介绍一款小众的IDE

    作为前端工程师的你们平时主要使用什么IDE,atom.webstorm.sublime还是vscode? 今天介绍一款比较小众的IDE,Adobe的开源项目Brackets,提供Windows和OS ...

  10. npm属性笔记

    scripts属性,运行脚本命令的npm命令行缩写,常见如下npm run devnpm run startnpm run build dependencies属性,项目运行时配置模块依赖的模块列表, ...