设计模式学习之——六大设计准则之五:迪米特法则
设计模式学习之——六大设计原则之五:迪米特法则
迪米特法则又称最少知识原则(Least Knowledge Principle, LKP)
解释1:一个对象应对其他对象有最少的了解
解释2:Only talk to your immedate friends(只与直接的朋友通信)
对类的低耦合提出明确要求:(4点)
1.只和朋友交流
eg:
老师教班长去清点班中女生人数(在老师类中初始化女生)
老师类:
public class Teacher { //老师对班长发布命令,清点女生 public void commond(GroupLeader groupLeader) { List<Girl> listGirls = new ArrayList(); //初始化女生 for (int i = 0; i < 20; i++) { listGirls.Add(new Girl()); //告诉班长开始执行清点任务 groupLeader.countGirls(listGirls); } } }班长类:
public class GroupLeader { //清点女生数量 public void countGirls(List<Girl> listGirls) { //输出女生数量:listGirls.size() } }女生类:
public class Girl { }场景类:
public class Client { public static void main(String[] args) { Teacher teacher = new Teacher(); //老师发布命令 teacher.commond(new GroupLeader()); } }
运行结果是:20
考虑程序中存在的问题:
先考虑Teacher类有几个朋友类?它仅有一个朋友类GroupLeader,为什么Girl不是朋友类呢?
朋友类的定义:出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。
现在我们看,Girl类就是出现在commond方法体内的,所以说 不属于Teacher类的朋友类。
所以,我们需要修改类关系图:
修改后的老师类:
public class Teacher { //老师对班长发布命令,清点女生 public void commond(GroupLeader groupLeader) { //告诉班长开始执行清点任务 groupLeader.countGirls(); } }修改后的班长类:
public class GroupLeader { private List<Girl> listGirls; public GroupLeader(List<Girl> _listGirls) { this.listGirls = _listGirls; } //清点女生数量 public void countGirls(List<Girl> listGirls) { //输出女生数量:this.listGirls.size() } }修改后的场景类:
public class Client { public static void main(String[] args) { //产生一个女生群体 List<Girl> listGirls = new ArrayList<Girl>(); //初始化女生 for (int i = 0; i < 20; i++) { listGirls.Add(new Girl()); } Teacher teacher = new Teacher(); //老师发布命令 teacher.commond(new GroupLeader(listGirls)); } }
简单修改程序,将Teacher中对女生的初始化放到了场景类中,同时在GroupLeader中增加了对Girl的注入,避开了Teacher类对陌生类Girl的访问,降低了系统间的耦合,提高了系统的健壮性。
注意:一个类只和朋友交流,不与陌生类交流,不要出现 getA().getB().getC().getD() 这种情况(除非每个点号后面的返回类型都相同),类与类间的关系是建立在类间的,而不是方法间的
2. 朋友间也是有距离的
eg:
安装软件时,会有导向动作,第一步做什么,第二步做什么等等,即是顺序执行。具体到程序中就是:调用一个或多个类,先执行第一个方法,然后第二个方法根据返回结果再来看是否可以调用第三个方法。
类关系图:
导向类:
public class Wizard { private Random rand = new Random(System.currentTimeMillis()); public int first() { //执行第一个方法 return rand.nextInt(100); } public int second() { //执行第二个方法 return rand.nextInt(100); } public int third() { //执行第三个方法 return rand.nextInt(100); } }
InstallSoftware类:
public class InstallSoftware { public void installWizard(Wizard wizard) { int first = wizard.first(); if (first > 50) { int second = wizard.second(); if (second > 50) { int third = wizard.third(); if (third > 50) wizard.first(); } } } }场景类:
public class Client { public static void main(String[] args) { InstallSoftware invoker = new InstallSoftware(); invoker.installWizard(new Wizard()); } }
现在,我们可以来看下程序中存在什么问题?Wizard把太多的方法暴露给InstallSoftware类,两者朋友类关系太亲密了,耦合关系变得异常牢固。
此时如果我们要将Wizard类中的first方法返回值的类型由int修改为boolean的话,就需要修改InstallSoftware类,从而把修改变更的风险扩散了。
因此这样的耦合是季度不合适的,重新设计吧!!重构后如下图:
在Wizard类中增加一个installWizard方法,对安装过程进行封装,同时,把原有的三个public方法改成private方法
修改后的导向类如下:
public class Wizard { private Random rand = new Random(System.currentTimeMillis()); private int first() { //执行第一个方法 return rand.nextInt(100); } private int second() { //执行第二个方法 return rand.nextInt(100); } private int third() { //执行第三个方法 return rand.nextInt(100); } //软件安装过程 public void installWizard() { int first = wizard.first(); if (first > 50) { int second = wizard.second(); if (second > 50) { int third = wizard.third(); if (third > 50) wizard.first(); } } } }这样Wizard类就只对外公布了一个public方法,即便修改first方法的返回值,影响的也仅仅只是Wizard本身,其他类不受影响,这就显示了类的高内聚性。
少量修改InstallSoftware类
public class InstallSoftware { public void installWizard(Wizard wizard) { //直接调用 wizard.installWizard(); } }注意:迪米特法则要求类“羞涩”一点,尽量不要对外公布太多public犯法和非静态的public变量,尽量内敛,多使用private,package-private、protected等访问权限。
3. 自己的就是自己的
原则:如果一个方法放在本类中,即不增加类间关系,也对本类不产生负面影响,就放置在本类中。
4. 谨慎使用Serializable
这个是项目管理的问题咯。小码农不考虑,略~
欢迎转载,转载注明出处,谢谢
Mr.傅:阅读自《设计模式之禅》