[设计模式之禅读书笔记]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的,当客户端的对象类发生变化的时候,如果服务器端的对象类没有对应的改变,那么就会发生序列化失败的情况。这种情况发生了,就属于整个软件系统的失败了。所以要注意一下。作者也并不是要我们不用,而是要我们谨慎使用。其实这一点跟迪米特也没多大的关系,呵呵。
总结
迪米特法则理解起来很简单,是的,很简单,但是实施起来到底该掌握到何种度 ,是需要我们千锤百炼的做项目总结出来的。总之,还是那句话,设计模式给你提供原则,给你提供模式,但是你不能非得用,有时会过犹不及的。