单一职责原则(Single Responsibility Principle)简称SRP原则。
定义
应该有且仅有一个原因引起类的变更。
优点
可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;
提高类的可读性,提高系统的可维护性;
变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。
说明
单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则;
单一职责原则要根据项目的实际情况去划分职责粒度,职责粒度划分太细容易引起职责扩散容易增加管理复杂度,职责粒度划分太粗则容易增高变更引起的风险;
示例
背景
假设有一做产品的小公司,因为是创业阶段,由于资金有限,公司机制不健全并且每个职工负责的职能较多,职工种类和职责分配如下表:
职工种类
职责分工
研发职工
需求分析,产品定义,产品设计,产品研发
销售职工
产品销售
假设公司由老板亲自驱动研发和销售的职工进行运作,运作流程为产品需求分析->产品定义->产品设计->产品开发->产品销售;
代码
首先看普通的代码实现:
执行结果:
李四进行产品需求分析
李四进行产品定义
李四进行产品设计
张三进行产品开发
王五进行产品销售
分析
对于上述代码,如果公司不断发展要增加一类产品职员,用来负责产品的需求分析,产品定义和产品设计。那么上述代码应该如何应对需求变更?一般情况下的做法是先生成一个Staff类的ProductStaff子类,让后让ProductStaff子类实现研发职责接口IDevResponsibility中:
public void requirementsAnalysis(); //需求分析
public void productDefine(); //产品定义
public void productDesign(); //产品设计
然后空实现:
public void productDevelop(); //产品开发
最后在Boss类中去掉DevelopStaff的相关职责功能,然后增加新的ProductStaff对象替代DevelopStaff中去掉的职责,具体代码如下:
运行结果:
修改该之后的代码也能完成任务,可是代码会变得晦涩难懂,此时的研发职工,仍然可以调用产品职工的相关职责,但是老板需要知道这些不用再去调用了;而且在看ProductStaff类的时候会变得理解困难为什么一个产品职工要实现研发职工的接口呢?
优化
鉴于以上问题,我们就需要对接口进行单一职责处理;首先将接口根据实际的分析进行职责粒度细化,本示例中,我们分析道可能会有一个产品职工种类出现,因此在接口设计阶段把职责首先划分为3类:产品职工职责,研发员工职责和销售员工职责;
当变更发生时
此时的代码将会显得更加逻辑合理,更加便于维护;
总结
接口设计尽量按照单一职责原则进行设计
类设计尽量按照只有一个原因引起类的变化进行设计
设计是有限度的,不能无限的考虑未来的情况
单一职责设计的前提是建立在客户对使用对象有充分了解的情况下的,实际上为了提高了客户的工作效率而增加了客户的工作并且方便了自己的管理。