英文名:Single Responsibility Principle,SRP 单一职责原则。这里的职责是指类变化的原因,单一职责原则规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分(There should never be more than one reason for a class to change)。
该原则提出对象不应该承担太多职责,如果一个对象承担了太多的职责,至少存在以下两个缺点:
一个职责的变化可能会削弱或者抑制这个类实现其他职责的能力;当客户端需要该对象的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余代码或代码的浪费。【例1】大学学生工作管理程序。
分析:大学学生工作主要包括学生生活辅导和学生学业指导两个方面的工作,其中生活辅导主要包括班委建设、出勤统计、心理辅导、费用催缴、班级管理等工作,学业指导主要包括专业引导、学习辅导、科研指导、学习总结等工作。如果将这些工作交给一位老师负责显然不合理,正确的做法是生活辅导由辅导员负责,学业指导由学业导师负责。
【例2】医院身体体检。
想必大家也有体检的经历,体检会分为不同类别的科室,例如一般检查室(身高,体重,视力等),抽血室,内科,外科,五官科,妇科,眼科等等,这些科室单一的检查人体的某一部位或者某几个部位,那么,为什么不将检查的所有内容分到一个科室,一次性检查完,其实这样会造成大家排队时间长,不能交替的进行体检,当 检查者一个项目没有完成的时候,还不能较好的进行其他项目的体检。并且每个体检科室一般不具有紧密的联系,把每个人体所需检查的部位划分为若干单元,每个单元的医师做自己份内的事情,还有助于体检高效的进行。
在软件开发设计的时候也是如此,对象包括对象的属性和方法,当我们设计接口的时候,有时候会出现有些问题,比如人的属性和行为全都放在一个接口中声明,这样就造成了业务对象和业务方法被放在了一起,接口有两种职责,违背了单一职责原则,正如下面的例子:
package com.lialir.chapterone; public interface Iexamine{ //检查身高 void setHeight(double height); double getHeight(); //检查体重 void setWeight(double weight); double getWeight(); //心率是否正常 boolean testHeartRate(int number); }以上的例子身高和体重本应该在一般体检科检查,而心率检查一般在内科,但是这就会给人一种不知道这个接口到底是做什么的感觉,职责不清晰,到底是一般检查科还是内科,后期维护的时候也会造成各种各样的问题。因此,解决办法是:单一职责原则,将这个接口分解成两个职责不同的接口即可。 体检科:
package com.lialir.chapterone; public interface IGerExamine{ //检查身高 void setHeight(double height); double getHeight(); //检查体重 void setWeight(double weight); double getWeight(); }内科:
package com.lialir.chapterone; public interface IHeartRateExamine{ //心率是否正常 boolean testHeartRate(int number); }单一职责原则的核心就是控制类的粒度大小、将对象解耦、提高其内聚性。如果遵循单一职责原则将有以下优点。
降低类的复杂度。一个类只负责一项职责,其逻辑肯定要比负责多项职责简单得多。提高类的可读性。复杂性降低,自然其可读性会提高。提高系统的可维护性。可读性提高,那自然更容易维护了。变更引起的风险降低。变更是必然的,如果单一职责原则遵守得好,当修改一个功能时,可以显著降低对其他功能的影响注意:单一职责同样也适用于方法。一个方法应该尽可能做好一件事情。如果一个方法处理的事情太多,其颗粒度会变得很粗,不利于重用。