迪米特法则又称最少知识原则(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.傅:阅读自《设计模式之禅》