设计模式学习之——六大设计原则之五:迪米特法则

来源:互联网 发布:sql语句查询两张表 编辑:程序博客网 时间:2024/06/03 21:36
迪米特法则又称最少知识原则(Least Knowledge Principle, LKP)
解释1:一个对象应对其他对象有最少的了解
解释2:Only talk to your immedate friends(只与直接的朋友通信)
对类的低耦合提出明确要求:(4点)
1.只和朋友交流
eg:
    老师教班长去清点班中女生人数(在老师类中初始化女生)

老师类:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class Teacher  
  2. {  
  3.     //老师对班长发布命令,清点女生  
  4.     public void commond(GroupLeader groupLeader)  
  5.     {  
  6.         List<Girl> listGirls = new ArrayList();  
  7.         //初始化女生  
  8.         for (int i = 0; i < 20; i++)  
  9.         {  
  10.             listGirls.Add(new Girl());  
  11.             //告诉班长开始执行清点任务  
  12.             groupLeader.countGirls(listGirls);  
  13.         }  
  14.     }  
  15. }  
班长类:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class GroupLeader  
  2. {  
  3.     //清点女生数量  
  4.     public void countGirls(List<Girl> listGirls)  
  5.     {  
  6.         //输出女生数量:listGirls.size()  
  7.     }  
  8. }  
女生类:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class Girl  
  2. {  
  3. }  
场景类:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class Client  
  2. {  
  3.     public static void main(String[] args)  
  4.     {  
  5.         Teacher teacher = new Teacher();  
  6.         //老师发布命令  
  7.         teacher.commond(new GroupLeader());  
  8.     }  
  9. }  
运行结果是:20

考虑程序中存在的问题:
    先考虑Teacher类有几个朋友类?它仅有一个朋友类GroupLeader,为什么Girl不是朋友类呢?
    朋友类的定义:出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。
    现在我们看,Girl类就是出现在commond方法体内的,所以说 不属于Teacher类的朋友类。

所以,我们需要修改类关系图:


修改后的老师类:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class Teacher  
  2. {  
  3.     //老师对班长发布命令,清点女生  
  4.     public void commond(GroupLeader groupLeader)  
  5.     {  
  6.         //告诉班长开始执行清点任务  
  7.         groupLeader.countGirls();  
  8.     }  
  9. }  
修改后的班长类:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class GroupLeader  
  2. {  
  3.     private List<Girl> listGirls;  
  4.     public GroupLeader(List<Girl> _listGirls)  
  5.     {  
  6.         this.listGirls = _listGirls;  
  7.     }  
  8.     //清点女生数量  
  9.     public void countGirls(List<Girl> listGirls)  
  10.     {  
  11.         //输出女生数量:this.listGirls.size()  
  12.     }  
  13. }  
修改后的场景类:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class Client  
  2. {  
  3.     public static void main(String[] args)  
  4.     {  
  5.         //产生一个女生群体  
  6.         List<Girl> listGirls = new ArrayList<Girl>();  
  7.         //初始化女生  
  8.         for (int i = 0; i < 20; i++)  
  9.         {  
  10.             listGirls.Add(new Girl());  
  11.         }  
  12.         Teacher teacher = new Teacher();  
  13.         //老师发布命令  
  14.         teacher.commond(new GroupLeader(listGirls));  
  15.     }  
  16. }  

简单修改程序,将Teacher中对女生的初始化放到了场景类中,同时在GroupLeader中增加了对Girl的注入,避开了Teacher类对陌生类Girl的访问,降低了系统间的耦合,提高了系统的健壮性。
注意:一个类只和朋友交流,不与陌生类交流,不要出现 getA().getB().getC().getD() 这种情况(除非每个点号后面的返回类型都相同),类与类间的关系是建立在类间的,而不是方法间的

2. 朋友间也是有距离的
eg:
安装软件时,会有导向动作,第一步做什么,第二步做什么等等,即是顺序执行。具体到程序中就是:调用一个或多个类,先执行第一个方法,然后第二个方法根据返回结果再来看是否可以调用第三个方法。
类关系图:

导向类:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class Wizard  
  2. {  
  3.     private Random rand = new Random(System.currentTimeMillis());  
  4.     public int first()  
  5.     {  
  6.         //执行第一个方法  
  7.         return rand.nextInt(100);  
  8.     }  
  9.    
  10.     public int second()  
  11.     {  
  12.         //执行第二个方法  
  13.         return rand.nextInt(100);  
  14.     }  
  15.    
  16.     public int third()  
  17.     {  
  18.         //执行第三个方法  
  19.         return rand.nextInt(100);  
  20.     }  
  21. }  
InstallSoftware类:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class InstallSoftware  
  2. {  
  3.     public void installWizard(Wizard wizard)  
  4.     {  
  5.         int first = wizard.first();  
  6.         if (first > 50)  
  7.         {  
  8.             int second = wizard.second();  
  9.             if (second > 50)  
  10.             {  
  11.                 int third = wizard.third();  
  12.                 if (third > 50)  
  13.                     wizard.first();  
  14.             }  
  15.         }  
  16.     }  
  17. }  
场景类:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class Client  
  2. {  
  3.     public static void main(String[] args)  
  4.     {  
  5.         InstallSoftware invoker = new InstallSoftware();  
  6.         invoker.installWizard(new Wizard());  
  7.     }  
  8. }  

    现在,我们可以来看下程序中存在什么问题?Wizard把太多的方法暴露给InstallSoftware类,两者朋友类关系太亲密了,耦合关系变得异常牢固。
    此时如果我们要将Wizard类中的first方法返回值的类型由int修改为boolean的话,就需要修改InstallSoftware类,从而把修改变更的风险扩散了。
    因此这样的耦合是季度不合适的,重新设计吧!!重构后如下图:


    在Wizard类中增加一个installWizard方法,对安装过程进行封装,同时,把原有的三个public方法改成private方法
修改后的导向类如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class Wizard  
  2. {  
  3.     private Random rand = new Random(System.currentTimeMillis());  
  4.     private int first()  
  5.     {  
  6.         //执行第一个方法  
  7.         return rand.nextInt(100);  
  8.     }  
  9.     private int second()  
  10.     {  
  11.         //执行第二个方法  
  12.         return rand.nextInt(100);  
  13.     }  
  14.     private int third()  
  15.     {  
  16.         //执行第三个方法  
  17.         return rand.nextInt(100);  
  18.     }  
  19.     //软件安装过程  
  20.     public void installWizard()  
  21.     {  
  22.         int first = wizard.first();  
  23.         if (first > 50)  
  24.         {  
  25.             int second = wizard.second();  
  26.             if (second > 50)  
  27.             {  
  28.                 int third = wizard.third();  
  29.                 if (third > 50)  
  30.                     wizard.first();  
  31.             }  
  32.         }  
  33.     }  
  34. }   
这样Wizard类就只对外公布了一个public方法,即便修改first方法的返回值,影响的也仅仅只是Wizard本身,其他类不受影响,这就显示了类的高内聚性。
少量修改InstallSoftware类
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class InstallSoftware  
  2. {  
  3.     public void installWizard(Wizard wizard)  
  4.     {  
  5.         //直接调用  
  6.         wizard.installWizard();  
  7.     }  
  8. }  
注意:迪米特法则要求类“羞涩”一点,尽量不要对外公布太多public犯法和非静态的public变量,尽量内敛,多使用private,package-private、protected等访问权限。

3. 自己的就是自己的
原则:如果一个方法放在本类中,即不增加类间关系,也对本类不产生负面影响,就放置在本类中。
4. 谨慎使用Serializable
    这个是项目管理的问题咯。小码农不考虑,略~





欢迎转载,转载注明出处,谢谢

Mr.傅:阅读自《设计模式之禅》

来源:http://blog.csdn.net/fu222cs98/article/details/21426339


0 0
原创粉丝点击