[设计模式之禅读书笔记]005_设计模式六大原则(五):迪米特原则

序言

   记得一年前看设计模式的时候,走马观花,囫囵吞枣。每一个概念都没有去仔细想,只是知道某某设计模式能干什么事。今天看到【迪米特原则】倍感莫名其妙,你说你叫接口隔离原则吧,我可以一个词一个词的去解析;你说你叫单一职责吧,看名字我就能知道什么用。你非得叫个什么迪米特原则,让人莫名其妙,跟里氏替换原则差不多,不过里氏替换至少还有个替换二字。今天我们就来看看这个迪米特原则到底是个什么原则吧.

正文

   迪米特,英文demeter,网上说是天空之神跟时光女神的女儿,是丰产、农林女神。这个天空之神跟时光之神还有一个叫宙斯(第三代神王)的儿子和一个叫哈德斯(冥界之主神)的儿子。这个宙斯跟迪米特,也就是自己的二姐结婚了(近亲啊!),他们生了一个女儿,叫Persephone,这个Persephone又被自己的叔叔哈德斯劫持,她叔叔想让她当冥后(近亲啊!)。然后我们的迪米特伤心欲绝,她到大地上漫无目的找自己的女儿。以至于忘了给大地生机,奥林匹斯山各位大神不高兴了,人间大地不能这样搞啊,于是迫使冥界之神哈德斯放了Persephone。其实也只有所有大神联合才能对冥王哈德斯说话,因为哈德斯是宙斯和迪米特的哥哥,他是四大创世神之一(四大创世神:哈德斯、波塞冬、宙斯、赫拉,可惜没有女娲)。这里扯一下,当年划分天下的时候,四个创世神是抽签决定的,力量最强的哈德斯抽到冥界,但他不是死神,他这人除了抢自己的侄女当老婆之外,其他都还好。

   额,说多了,有时间仔细研究一下西方的神话史——荷马史诗,然后写篇博客介绍一下。这里我们的demeter只是一个寻找女儿的母亲而已,并没有什么特殊的含义,那迪米特原则到底是什么意思呢?

一个对象应该对其他对象有最少的了解。

   可能只有这句话还是不能理解这个原则吧!毕竟只是一句话,你说理解了,是的,你只是知道这句话而已,这句话背后的含义,就不一定了,下面我们来仔细看看吧!

1. 迪米特法则的根本意图——解耦合

   二战期间,有一段时间德国战神,沙漠之狐隆美尔在家休假,这时候,他辛苦打下的北非被一个英国大叔——蒙哥马利攻击了。我们的元首希特勒就找到隆美尔,对他说:小隆啊,你带几万兵把蒙哥马利给干死吧!

     

   我们现在有三个类了,看代码,这里先提示一下,类希特勒是有问题的

 1 class 希特勒{
 2 public:
 3     void  killMeng(隆美尔 l){
 4           vector<德国大兵> list;           // 这里我们的元首其实是没有闲心跟小兵打交道的,但是我们在希特勒的世界里却看到了这些小兵的身影了
 5           for(int i = 0; i < 100000; i++){
 6               list.add(new 德国大兵());
 7           }
 8           l.gotoKillMeng(list);
 9     }
10 };
11 
12 class 隆美尔{
13 public:
14     void gotoKillMeng(vector<德国大兵> list){
15           for(int i = 0; i < 100000; i++){
16               list.get(i).gotoNorthAfrica();
17           }
18     }
19 };
20 
21 class  德国大兵{
22 public:
23      void gotoNorthAfrica(){
24           cout<<"I am going to North Africa."<<endl;
25      }
26 };

   从上面的注释可以看出来问题,我们的元首直接操作命令隆美尔就可以了,完全没有去亲自招兵买马嘛!这里我们的元首跟小兵就耦合了,实际上也是完全没有必要耦合到一起的。我们要在元首希特勒的类里把关于德国大兵的代码干掉,那么谁与这些大兵直接关联呢?当然是我们的隆美尔大神了,那么这些个大兵的代码应该放到隆美尔的类里,修改后的代码如下:

 1 class 希特勒{
 2 public:
 3     void  killMeng(隆美尔 l){       // 直接命令隆美尔大神就可以了
 4 
 5           l.gotoKillMeng();
 6     }
 7 };
 8 
 9 class 隆美尔{
10 public:
11     void gotoKillMeng(){
12           vector<德国大兵> list;
13           for(int i = 0; i < 100000; i++){   // 我们的隆美尔大神来招兵组队
14               list.add(new 德国大兵());
15           }
16           for(int i = 0; i < 100000; i++){
17               list.get(i).gotoNorthAfrica();
18           }
19     }
20 };
21 
22 class  德国大兵{
23 public:
24      void gotoNorthAfrica(){
25           cout<<"I am going to North Africa."<<endl;
26      }
27 };

2. 迪米特法则注意事项(一)——密切关联的类之间不能太过亲近,要提高内聚

   这个也很容易明白,我就不举代码例子了,时间不早了,要睡觉了。比如虽然我们的元首能够指挥隆美尔,但是隆美尔大神也有自己的私生活空间嘛!元首肯定不能去介入人家的私生活的。那怎么控制元首对隆美尔私生活的介入呢?用我们的private关键字,这样的话,不想让元首使用的方法就可以隐藏起来了。

3. 迪米特法则注意事项(二)——是自己的就是自己的

   这个是什么意思呢?比如有一个方法,放到A类里也可以,放到B类里也可以,那怎么办呢?其实不用纠结到底该 放到哪里。迪米特法则给我们一个解决方案:

如果一个方法放在本类中,即不增加类间的关系,也对本类不会产生负面影响,就放置在类中。

4. 迪米特法则注意事项(三)——谨慎使用序列化

   序列化用于序列对象内存数据,使其可以通过不同的媒介传输。但是,如果我们的软件系统模型是C/S的,当客户端的对象类发生变化的时候,如果服务器端的对象类没有对应的改变,那么就会发生序列化失败的情况。这种情况发生了,就属于整个软件系统的失败了。所以要注意一下。作者也并不是要我们不用,而是要我们谨慎使用。其实这一点跟迪米特也没多大的关系,呵呵。

总结

   迪米特法则理解起来很简单,是的,很简单,但是实施起来到底该掌握到何种度 ,是需要我们千锤百炼的做项目总结出来的。总之,还是那句话,设计模式给你提供原则,给你提供模式,但是你不能非得用,有时会过犹不及的。

posted @ 2012-10-26 00:01  邵贤军  阅读(1861)  评论(3编辑  收藏  举报