代码改变世界

瑞士军刀 VS 单一职责原则

2009-08-28 19:07 鹤冲天 阅读(...) 评论(...) 编辑 收藏
 “单一职责原则”是面向对象软件开发的基本原则之一,面向对象的思想又是从现实世界中总结出来。可最近发现面向对象的单一职责原则与现实好似有些冲突。

 我们先看下引起事非争端的优雅的瑞士军刀吧:

  

 瑞士军刀都是多功能工具刀,上面左图的至少有14项功能,右图的至少有34项功能!

 

 

 这个是带MP3播放功能的!还有更加强大的:
        

 这是知名瑞士刀制造商,威戈(Wenger)最新推出了一把长8.75英寸、重2磅(1公斤)内含87种工具的瑞士刀,编号16999。看来几乎曾经出现在瑞士刀里头的东西都有了,它包括七种不同的小刀、高尔夫球鞋清理钳、脚踏车链铆钉调整器,还有一只测距达300英尺(90公尺)的雷射笔。这把瑞士刀的作用,可能是让一个当打完高尔夫球的人,能够在清理完自己的球鞋以后,马上把脚踏车给调校好,接着骑到一个人烟罕至的树林里。

 这个是相当“变态”的,我最近一直在写扩展方法的文章,所有文章中的扩展方法合在一起也和军刀有点类似了。

 瑞士军刀和普通的刀(单一职责设计的刀)最大的不同就是方便(先不考虑最后一个,哈哈),它是多功能刀,而不是简简单单的刀。从功能上看,瑞士军刀“打破”了单一职责原则。也许产品的设计和软件系统的设计不能相提并论,毕竟归规模、复杂度相差太远。单一职责原则是为解决复杂问题而制定的。那我们就换个思路去考虑,我们构建一支军队,现在要给士兵配一些装备。军队、士兵、装备全是对象!有点类似了吧。我们是给士兵配一把多功能的瑞士军刀,还是配很多很多零散的小工具呢? 

 以上的对比可能不恰当,但从中可推出一个结论:有时使用单一职责,没看到好的效果,反而更麻烦。

 先来看下单一职责原则(Single-Responsibility Principle)的定义,Robert C. Martin对它的解释是:Each class should have one and only one reason to change. 单一职责并不是直观理解为类只能有单一的功能,单一职责是从变化的角度去考虑的。一个类应该(注意是should而不是must,是应该而不是必须)有且只有一个因起它变化的原因(直译)。

 Martin的解释改变的单一职责原则的含义:

 1.“单一职责”不是指具有单一功能(而是只因一个原因变化);

 2.“原则”更像是一种比较强烈的建议。


 基于这两点理解,引发出我的观点:

 1.对象颗粒大小不同,对小颗粒对象应用单一职责是不合适的:小颗粒对象如小公司的员工,需要一人兼数职。如果应用单一职责,小颗粒对象又将分解成更多更小颗粒的对象,数量越来越多,给我们命名、使用、维护带来麻烦。

 2.基础类库不适合:比如字符串常用处理的类,取子字符串、转换为其它类型、为空判断,放在一个类中反而使用更方便!

 3.“单一职责原则”更适于中大型系统,系统越小使用该原则越不划算:一超个小系统就一个界面,面象对象都不必使用。

 4.单一职责当然要用,但不是用到每个细节:一些局部不用对整体影响很小,反而更灵活、更省时间。 

 4.原则是前辈能多年的经验总结出来的,原则的名字可能不变,但原则的内含可能在悄悄变化。

 5.“principle”、“原则”有可能是前人一种表达强烈建议的方式,而不是“must”、“必须”。

 

 再回头看前面的军刀,它有多种功能,但能引起它变化的原因是什么呢?这里想到一个,客户应用。根据客户的具体应用,会有多种功能组合,不同组合又分成不同系列...客户有了新的需求,就会推出新产品...这个过程中可能包含了对象的继承、组合等等,应该很复杂。当然也遇到客户需求相当相当不一般,所以推出前面很变态的那款,应该算个特例吧!

 再考虑:军刀上有一个开啤酒瓶用的启子,如果啤酒瓶的盖子大小变了呢?带MP3功能的军刀上有耳机插孔,耳机接口变了怎么办?仔细想想,能引起它变化的原因还真不少。但这些变化发生的可能性太小了,即便是真的发生了,军刀该退役了,新品就推出了。 

 所以,我认为瑞士军刀还是比较符合单一职责原则的!前面推出的结论“有时使用单一职责,没看到好的效果,反而更麻烦”,有两种解释: 

 1.将单一职责错误理解成了单一功能,又进一步去分解功能,所以麻烦;

 2.不分对象大小,不看程序规模,统统使用:用的不恰当,所以麻烦。 


 最后结论,面向对象的思想与原则与现实世界是一致的,并且与时俱进。

 本人没有受过正规的软件教育,对面向对象理解也是残缺不全,对技术也是东一块西一块,杂乱的想法也很多。说的不对请各位前辈指正!