单一职责原则(Single Responsibility Principle)
定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
问题由来:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。
解决方案:遵循单一职责原则。分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职责P2功能。这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使职责P1发生故障风险。
说到单一职责原则,很多人都会不屑一顾。因为它太简单了。稍有经验的程序员即使从来没有读过设计模式、从来没有听说过单一职责原则,在设计软件时也会自觉的遵守这一重要原则,因为这是常识。在软件编程中,谁也不希望因为修改了一个功能导致其他的功能发生故障。而避免出现这一问题的方法便是遵循单一职责原则。虽然单一职责原则如此简单,并且被认为是常识,但是即便是经验丰富的程序员写出的程序,也会有违背这一原则的代码存在。为什么会出现这种现象呢?因为有职责扩散。所谓职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2。
比如:类T只负责一个职责P,这样设计是符合单一职责原则的。后来由于某种原因,也许是需求变更了,也许是程序的设计者境界提高了,需要将职责P细分为粒度更细的职责P1,P2,这时如果要使程序遵循单一职责原则,需要将类T也分解为两个类T1和T2,分别负责P1、P2两个职责。但是在程序已经写好的情况下,这样做简直太费时间了。所以,简单的修改类T,用它来负责两个职责是一个比较不错的选择,虽然这样做有悖于单一职责原则。
举例说明,用一个类描述动物呼吸这个场景:
class Animal{
public void breathe(String animal){
System.out.println(animal+"呼吸空气");
}
}
public class Client{
public static void main(String[] args){
Animal animal = new Animal();
animal.breathe("牛");
animal.breathe("羊");
animal.breathe("猪");
}
}
运行结果:
牛呼吸空气
羊呼吸空气
猪呼吸空气
程序上线后,发现问题了,并不是所有的动物都呼吸空气的,比如鱼就是呼吸水的。修改时如果遵循单一职责原则,需要将Animal类细分为陆生动物类Terrestrial,水生动物Aquatic,代码如下:
class Terrestrial{
public void breathe(String animal){
System.out.println(animal+"呼吸空气");
}
}
class Aquatic{
public void breathe(String animal){
System.out.println(animal+"呼吸水");
}
}
public class Client{
public static void main(String[] args){
Terrestrial terrestrial = new Terrestrial();
terrestrial.breathe("牛");
terrestrial.breathe("羊");
terrestrial.breathe("猪");
Aquatic aquatic = new Aquatic();
aquatic.breathe("鱼");
}
}
运行结果:
牛呼吸空气
羊呼吸空气
猪呼吸空气
鱼呼吸水
我们会发现如果这样修改花销是很大的,除了将原来的类分解之外,还需要修改客户端。而直接修改类Animal来达成目的虽然违背了单一职责原则,但花销却小的多,代码如下:
class Animal{
public void breathe(String animal){
if("鱼".equals(animal)){
System.out.println(animal+"呼吸水");
}else{
System.out.println(animal+"呼吸空气");
}
}
}
public class Client{
public static void main(String[] args){
Animal animal = new Animal();
animal.breathe("牛");
animal.breathe("羊");
animal.breathe("猪");
animal.breathe("鱼");
}
}
可以看到,这种修改方式要简单的多。但是却存在着隐患:有一天需要将鱼分为呼吸淡水的鱼和呼吸海水的鱼,则又需要修改Animal类的breathe方法,而对原有代码的修改会对调用“猪”“牛”“羊”等相关功能带来风险,也许某一天你会发现程序运行的结果变为“牛呼吸水”了。这种修改方式直接在代码级别上违背了单一职责原则,虽然修改起来最简单,但隐患却是最大的。还有一种修改方式:
class Animal{
public void breathe(String animal){
System.out.println(animal+"呼吸空气");
}
public void breathe2(String animal){
System.out.println(animal+"呼吸水");
}
}
public class Client{
public static void main(String[] args){
Animal animal = new Animal();
animal.breathe("牛");
animal.breathe("羊");
animal.breathe("猪");
animal.breathe2("鱼");
}
}
可以看到,这种修改方式没有改动原来的方法,而是在类中新加了一个方法,这样虽然也违背了单一职责原则,但在方法级别上却是符合单一职责原则的,因为它并没有动原来方法的代码。这三种方式各有优缺点,那么在实际编程中,采用哪一中呢?其实这真的比较难说,需要根据实际情况来确定。我的原则是:只有逻辑足够简单,才可以在代码级别上违反单一职责原则;只有类中方法数量足够少,才可以在方法级别上违反单一职责原则;
例如本文所举的这个例子,它太简单了,它只有一个方法,所以,无论是在代码级别上违反单一职责原则,还是在方法级别上违反,都不会造成太大的影响。实际应用中的类都要复杂的多,一旦发生职责扩散而需要修改类时,除非这个类本身非常简单,否则还是遵循单一职责原则的好。
遵循单一职责原的优点有:
l 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;
l 提高类的可读性,提高系统的可维护性;
l 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。
需要说明的一点是单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都需要遵循这一重要原则。
相关推荐
一、单一职责原则(SRP) 就一个类而言,应该仅有一个引起它变化的
主要介绍了PHP面向对象五大原则之单一职责原则(SRP),结合实例形式详细分析了单一职责原则(SRP)的概念、原理、定于与使用方法,需要的朋友可以参考下
面向对象 设计原则 单一职责原则--SRP 开放封闭原则--OCP Liskov替换原则--LSP 依赖倒置原则--DIP 接口隔离原则--ISP
1. 针对特定平台(编程语言、操作系统、数据库、框架、 2. 应用面向对象设计的原则与模式进行优化 1. 单一职责原则SRP 2. 里氏替换原则LSP 3. 依
前言 Bob大叔提出并发扬了S.O.L.I.D五大原则,用来更好地进行面向对象编程,五大原则分别是: The Single Responsibility Principle(单一职责SRP) The Open/Closed Principle(开闭原则OCP) The Liskov ...
单一职责原则 srp(Single Responsibility Principle) 2. 里氏替换原则 lsp(Liskov Substitution Principle) 3. 依赖倒置原则 dip(Dependence Inversion Principle) 4. 接口隔离原则 isp(interface-segregation ...
1、单一职责原则单一职责原则(SRP:Single responsibility principle)又称单一功能原则,面向对象五个基本原则(SOLID)之一
面向对象设计原则 单一职责原则--SRP 开放封闭原则--OCP Liskov替换原则--LSP ===
1、 IOS设计模式的六大设计原则之单一职责原则(SRP,Single Responsibility Principle) 定义 就一个类而言,应该仅有一个引起它变化的原因。 定义解读 这是六大原则中最简单的一种,通俗点说,就是不存在多个...
1.单一职责原则(Single Resposibility Principle,SRP) 专注是一个人的优良品质,同样,单一职责也是一个类的优良设计。单一职责的核心思想:一个类只做好一件事情。 单一职责原则可以看作是高内聚、低耦合在面向...
单一职责原则(SRP:Single responsibility principle),规定一个类中应该只有一个原因引起类的变化。 单一职责原则的核心就是解耦和增强内聚性。 问题: // 假设此类是数据库上下文 public class DatabaseContext...
单一职责原则——SRP 开放封闭原则——OCP Liskov替换原则 —— LSP 依赖倒置原则—— DIP 接口隔离原则—— ISP
4 单一职责原则-Single Responsibility Principle (SRP) 5 开闭原则-The Open-Closed Principle (OCP) 二 包的设计原则 6 重用发布等价原则-Release Reuse Equivalency Principle (REP) 7 无环依赖...
单一职责原则(SRP)、开放-封闭原则(OCP)、Liskov替换原则(LSP)、依赖倒置原则(DIP)、接口分离原则(ISP)
单一职责原则(Single Responsibility Principle,SRP):一个类应该只有一个引起它变化的原因,即一个类应该只有一个职责。这个原则鼓励将不同的功能分离到不同的类中,以减少类的复杂性,提高代码的可维护性。 ...
第8章 单一职责原则(SRP) 第9章 开放—封闭原则(OCP) 第10章 Liskov替换原则(LSP) 第11章 依赖倒置原则(DIP) 第12章 接口隔离原则(ISP) 第III部分 薪水支付案例研究 第13章 COMMAND模式和ACTIVE ...
8.1 单一职责原则(SRP) 8.2 结论 参考文献 第九章 开放—封闭原则(OCP) 9.1 开放—封闭原则(OCP) 9.2 描述 9.3 关键是抽象 9.4 结论 参考文献 第十章 Liskov替换原则(LSP) 10.1 Liskov替换原则(LSP) 10.2 ...
设计模式的原则(SOLID)1 单一职责原则 (SRP):每一个引起类变化的原因就是一个职责,当类具有多职责时,应把多余职责分离出去,分别创建一些类来完成每一个
SRP 单一职责原则 就一个类而言,应该仅有一个引起它变化的原因。 OCP 开放←封闭原则 软件实体(类、模块、函数等)应该是可以扩展的,但是不可修改ω LSP Liskov 替换原则 子类型必须能够替换掉它们的基类型。 DIP ...