类设计原则之 - 单一职责
类的设计原则之单一职责原则,是最常用的类的设计的原则之一
英文: SRP , Simple Responsibility Principle
中文:单一职责原则
这是面向对象类设计
中的第一个原则 ,也是看起来最简单的一个原则,但是实际上远远没有这么简单,很多人不一定真正理解了!
类设计,通俗的讲就是怎么去写一个类更好,应该遵循什么样的原则设计类更好。
我们随便找几个网上的解释:看看各位大师或者经典网站是怎么解释的。
百度百科:就一个类而言,应该仅有一个引起它变化的原因。应该只有一个职责。
说句实在话,我最开始也是对这句话似懂非懂,看的不是太明白,因为,引起一个类变化 的原因太多了,比如
- 给类增加一个方法是变化吧?
- 给类增加一个属性是变化吧?
- 给类的方法增加一个函数是变化吧?
- ......
引起这些变化的原因太多了,如果每个原因都是一个职责,那么SRP简直就无法判断了!
维基百科:(内容基本上和百度百科一致),通俗的讲就是:一个类只做一件事
这个解释更通俗易懂,也更符合中国人的理解。但是仔细想想,还是有几个地方比较难理解:
什么叫做 “一件事” ?
举个例子:
比如有一个学生管理类,这个类有 添加学生信息
, 修改学生信息
, 查询学生信息
, 删除学生信息
问题来了, 这是 4 件事 ? 还是 1 件事 ?
看起来好像是 4 件事, 但是稍有经验的人都知道,这 4 件事都是由一个类来实现的,而不是设计 4 个类!
所以问题的关键在于:什么是 “一件事” ? 是每个功能一件事吗?
其实答案就在我们自己身上, 因为只要我们工作,就无时无刻的在承担着一定的职责
现在抛开面向对象,抛开软件,抛开计算机,来看看我们自己的职责
- 比如我是一个程序员,我的职责是
写程序
, 但写程序
有很多事情,例如编码
,单元测试
,系统测试
,bug修复
,开会
,写文档
等 - 比如我的老板是一个管理者,他的职责是
管理程序员
,他也有很多工作,例如制订计划
,团队建设
,开会
,协调
绩效考评
等 - 比如我是一个快递员,我的职责是送快递,但是我也有很多事要做,例如
分包
,快递
,收款
,开会
等
这些职责都不是我们自己定义的,而是公司或者部门或者组织,给我们安排工作的时候定义的。
也就是说,职责
是站在他人的角度上定义的,而不是我们自己定义的。
经过我们对职责
定义的分析,我们可以得出 2 个关于职责的重要结论
- 职责是站在他人的角度上定义的
- 职责不是一件事,而是很多事,但这些事都是和职责紧密结合的。
对应到面向对象设计领域,我们可以说一个类的职责应该如下定义:
- 类的职责是站在其它类的角度来定义的
- 类的职责包含多个相关功能
因此,SRP
可以翻译为 一个类只负责一组相关的事
, 对应到代码中就是:一个类有多个方法,这些方法是相关的
有了这个定义,我们再来看看学生信息管理类
, 很明显,它具有的 4 个功能都是和 管理
相关的,按照 SRP
应该只设计一个学生信息管理类
就可以了。
欢迎关注我们的 HelloWorld开发者社区, www.helloworld.net ,很好记的域名哦
SRP 的应用范围
但是现实世界往往比理想更复杂,一个最典型的例子就是 办公一体化
根据 SRP , 打印机可以设计成一个类,复印机可以设计成一个类,扫描仪可以设计成一个类,传真机也可以设计成一个类
但偏偏就出了一个 办公一体化
, 这个机器集成了 打印
, 复印
, 扫描
, 传真
4 个职责 !
如果我们设计一个 办公一体化
的类,怎么也不可能设计出一个符合 SRP 的 办公一体化的类
!
怎么办? 是 SRP 不正确 ? 还是我们永远都不要设计一个 办公一体化
的类 ?
其实 SRP 没有错, 办公一体化
也应该设计, 但是不要用 SRP 原则来约束 办公一体化
这样的类!
也就是说, SRP 其实是有适用范围的, SRP 只适合那些基础类,而不适合基于基础类构建复杂类的聚合类
在办公一体化
的样例中, 打印机
,复印机
,扫描仪
,传真机
都是基础类,每个类都承担一个职责
而 办公一体化
是一个聚合类, 同时集成了4种功能!
细心的你可能发现了:SRP不能应用于聚合类, 那么如何保证聚合类的设计质量呢?
换句话说,遇到这样的情况,如何设计这样的聚合类呢?
这个问题在 GoF 的 《设计模式》 一书中有详细的答案,即优先使用对象组合 ,而不是类继承。
类的单一原则就到这里了,现小结一下:
- 类的单一原则(SRP):一个类只负责一组相关的事, 对应到代码中就是:
一个类有多个方法,这些方法是相关的
- 职责是站在他人的角度上定义的
- 类的职责包含多个相关功能
- SRP 只适合那些基础类,而不适合基于基础类构建复杂类的聚合类
- 对于复杂的聚合类,优先使用组合 ,而不是继承
- 最后一条,欢迎关注我们的
HelloWorld开发者社区
, 网址:www.helloworld.net
,域名很好记哦
欢迎关注我们的下一篇文章,出讲解更多的类设计的原则。