参考书籍:设计模式之禅--秦小波
上篇回顾:上篇讲到了接口隔离原则(ISP),讲的不好还请见谅。上篇文末留下了一个问题:“如果接口隔离原则和单一职责原则发生了冲突,鱼和熊掌如何取舍?”我们知道单一职责原则是站在业务的角度,接口隔离原则是站在接口功能定义角度。细分接口功能,很容易将一个完整的业务功能分割开来。这个时候我们切记:坚持单一职责原则!为什么呢?上篇说到,接口隔离原则细分的度没有统一的标准,过度细分会导致系统复杂度的增加,鉴于此,在业务体和接口细分产生冲突时,要优先保证单一职责原则。
迪米特法则:迪米特法则(Law of Demeter,LoD)也称为最少知识原则(Least Knowledge
Principle,LKP),虽然名字不同,但描述的是同一个规则。第二个名字表述的更加直白:一个类具体是怎么执行业务的我不需要知道,你只要告诉我调用那个方法就可以了。怎样才算是告诉我有哪些方法?没错,public。类的所有public 方法和变量都认为是对我公开的。也就是说:一个类对象,应该对其他的类对象的方法、变量知道的越少越好(对外开放的public类型的方法和变量应该越少越好)。
如何理解迪米特法则?我们分为3个方面来理解:
1.不要出现不相关的类依赖
什么意思?就是说,如果这个类的出现对我没什么用处,那么不要引入进来,go anywhere they want。大家可能会说,不用的类我们怎么会引用呢,但其实这个地方非常容易忽略,我们以下面老板和秘书出差的故事为例:
老板和秘书要出远门,出远门当然要先买机票,这个时候秘书就该上场啦:
class Boss{
//让秘书去买票
public void ask(){
Ticket ticket=new Ticket();
Secretary s=new Secretary();
s.buyTicket(ticket);
}
}
//秘书
class Secretary{
public void buyTicket(Ticket ticket)
{
ticket.user="Jack Ma";
}
}
class Ticket{
private String price;
private String user;
......
}
上面的Boss让秘书买票,秘书(Secretary)买票,先找到了航班,然后买了老板的票。这个过程中,Boss类中出现了Ticket(机票)类,这个合理吗?按照事物的执行逻辑,确实需要用到秘书,用到机票,才能完成购票的过程。但是买票是秘书要做的事情,老板并不应该知晓具体过程,也无需了解执行的过程。我们再从代码的设计角度看这个问题,如果我们后期修改了Ticket的业务逻辑,那我们免不了要检查所有依赖Ticket类的类,对修改造成的风险进行评估。最最主要的是,车票变了,老板无需关注,这是秘书应该关心的事情,对吗?
我们作如下修改:
class Boss{
//让秘书去买票
public void ask(){
Secretary s=new Secretary();
s.buyTicket();
}
}
//秘书
class Secretary{
public void buyTicket()
{
Ticket ticket=new Ticket();//车票被秘书私有-陈奕迅
ticket.user="Jack Ma";
}
}
class Ticket{
private String price;
private String user;
......
}
这样是不是就没有了刚刚的担忧,Ticket的只和秘书有关系,现在老板终于可以安枕无忧了。
2.尽量不要过度了解依赖的类
我们常说亲密有间,意思是,对一个人了解的太多,就会遇到更多的烦恼,适当的距离可以产生美。上面说老板和秘书要出差,需要安排行程,我们假设公司里有两个实习的秘书:
class Boss{
//让秘书A准备出差行程
SecretaryA a=new SecretaryA();
a.buyTicket();
a.prepareHotel();
a.prepareFood();
a.preareMeeting();
//让秘书B准备出差行程
SecretaryB b=new SecretaryB();
b.prepare();
}
//秘书A
class SecretaryA{
public void buyTicket(){}
public void prepareHotel(){}
public void prepareFood(){}
public void preareMeeting(){}
}
//秘书B
class SecretaryB{
private void buyTicket(){}
private void prepareHotel(){}
private void prepareFood(){}
private void preareMeeting(){}
public prepare(){
buyTicket();
prepareHotel();
prepareFood();
preareMeeting();
}
}
如果老板是你,你会欣赏哪个秘书?相信大家遇到秘书A一定会默默流泪,我要这个秘书有何用,所有的事情都需要我亲自过问,反观秘书B,你只需要说一句:安排下行程,剩下的统统不用管了,逍遥快活,也是一匹沙漠骆驼。上面的例子告诉我们,不要过多的使用public,做一个羞涩的类,把自己的事情放在心底,只让自己知道(多使用private)。
3.如何决定方法的去留
在实际应用中经常会出现这样一个方法:放在本类中也可以,放在其他类中也没有错,
那怎么去衡量呢?你可以坚持这样一个原则:如果一个方法放在本类中,既不增加类间关
系,也对本类不产生负面影响,那就放置在本类中。
总结:迪米特法则的核心思想就是:解耦!解耦!解耦!不需要的坚决不要,不相关的坚决不了解,这样,类将会更加单纯,更加原子,更加可扩展。
每篇一问:
迪米特法则让类之间联系更加独立,这可能导致两个类之间要想访问需要跨过好几层关系,那么怎么判断是否需要继续解耦呢?