彻底弄懂类设计原则之 - 单一职责原则

待兔 等级 796 0 0

类设计原则之 - 单一职责

类的设计原则之单一职责原则,是最常用的类的设计的原则之一

英文: SRP , Simple Responsibility Principle

中文:单一职责原则

这是面向对象类设计中的第一个原则 ,也是看起来最简单的一个原则,但是实际上远远没有这么简单,很多人不一定真正理解了!

类设计,通俗的讲就是怎么去写一个类更好,应该遵循什么样的原则设计类更好。

我们随便找几个网上的解释:看看各位大师或者经典网站是怎么解释的。

百度百科:就一个类而言,应该仅有一个引起它变化的原因。应该只有一个职责。

说句实在话,我最开始也是对这句话似懂非懂,看的不是太明白,因为,引起一个类变化 的原因太多了,比如

  • 给类增加一个方法是变化吧?
  • 给类增加一个属性是变化吧?
  • 给类的方法增加一个函数是变化吧?
  • ......

引起这些变化的原因太多了,如果每个原因都是一个职责,那么SRP简直就无法判断了!

维基百科:(内容基本上和百度百科一致),通俗的讲就是:一个类只做一件事

这个解释更通俗易懂,也更符合中国人的理解。但是仔细想想,还是有几个地方比较难理解:

什么叫做 “一件事” ?

举个例子:

比如有一个学生管理类,这个类有 添加学生信息 , 修改学生信息查询学生信息删除学生信息

问题来了, 这是 4 件事 ? 还是 1 件事 ?

看起来好像是 4 件事, 但是稍有经验的人都知道,这 4 件事都是由一个类来实现的,而不是设计 4 个类!

所以问题的关键在于:什么是 “一件事” ? 是每个功能一件事吗?

其实答案就在我们自己身上, 因为只要我们工作,就无时无刻的在承担着一定的职责

现在抛开面向对象,抛开软件,抛开计算机,来看看我们自己的职责

  1. 比如我是一个程序员,我的职责是写程序 , 但 写程序 有很多事情,例如 编码单元测试系统测试bug修复开会写文档
  2. 比如我的老板是一个管理者,他的职责是 管理程序员 ,他也有很多工作,例如 制订计划 , 团队建设开会 ,协调 绩效考评
  3. 比如我是一个快递员,我的职责是送快递,但是我也有很多事要做,例如 分包 , 快递 ,收款 , 开会

这些职责都不是我们自己定义的,而是公司或者部门或者组织,给我们安排工作的时候定义的。

也就是说,职责 是站在他人的角度上定义的,而不是我们自己定义的。

经过我们对职责 定义的分析,我们可以得出 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 ,域名很好记哦

欢迎关注我们的下一篇文章,出讲解更多的类设计的原则。

收藏
评论区

相关推荐

Python入门之类(class)
Python3 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。 如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对
Python入门之类(class)
Python3 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。 如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对
CAS之基本类型与引用类型
CAS之基本类型与引用类型 ============= 1.1 long -------- static final Unsafe unsafe ; static Long offset; private volatile long state= 1; static { try {
Java 类之间的关系
总述 == 类和类之间的关系,耦合度从高到低: * is 。继承、实现 * has 。组合、聚合、关联 * use 。依赖。 要求是:**高内聚、低耦合。** 继承 == Person 和 Man之间是继承关系。 ![](https://oscimg.oschina.net/oscnet/7b9f06e3a37b7bc9c5c2fe14
Java——类之间的关系
### 3.7 类之间的关系 #### 3.7.1 泛化关系  类和类之间的继承关系及接口与接口之间的继承关系。 ![](https://oscimg.oschina.net/oscnet/a5fa467c0401d4d7c7525fa4ab75fa4c672.png)  ![](https://oscimg.oschina.net/oscnet/9
Java基础之类
一、类的一般形式 -------- ### 1、类的概述 类就是事物的集合和抽象。它所代表的是这类事物所共有的一些行为和属性。 ### 2、类的一般形式 中国有13亿人,就有13亿个对象 人类只有一个 class 类名{ 类型 变量名; 类型 变量名; ... 类型 方法名
Java常用工具类之IO流工具类
package com.wazn.learn.util; import java.io.Closeable; import java.io.IOException; /** * IO流工具类 * * @author yangzhenyu *
java常用API之System类
System中代表程序所在系统,提供了对应的一些系统属性信息,和系统操作。System类不能手动创建对象,因为构造方法被private修饰,阻止外界创建对象。System类中的都是static方法,类名访问即可。 常用方法: ![](https://images2018.cnblogs.com/blog/1451598/201808/1451598-20
06_java之类概述
### 01引用数据类型\_类 * A: 数据类型 * a: java中的数据类型分为:基本类型和引用类型 * B: 引用类型的分类 * a: Java为我们提供好的类,比如说:Scanner,Random等。 * b: 我们自己创建的类,按照类的定义标准,可以在类中包含多个方法与属性,来供我
JUnit5学习之三:Assertions类
### 欢迎访问我的GitHub [https://github.com/zq2599/blog\_demos](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2Fzq2599%2Fblog_demos) 内容:所有原创文章分类汇总及配套源码,涉及Java、Doc
JUnit5学习之二:Assumptions类
### 欢迎访问我的GitHub [https://github.com/zq2599/blog\_demos](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2Fzq2599%2Fblog_demos) 内容:所有原创文章分类汇总及配套源码,涉及Java、Doc
Lua之Lua变量类型
在上一节中说到了 [Lua的安装与变量](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fwww.ttlsa.com%2Flua%2Flua-install-and-lua-variable-ttlsa%2F),这节说说Lua变量的类型。Lua在使用中不需要预先定义变量的类型。Lua中基本的类
Mongodb之数据类型
一.MongoDB的数据类型 -------------- Object  ID :Documents 自生成的 \_id String: 字符串,必须是utf-8 Boolean:布尔值,true 或者false (Python中 True False 首字母大写) Integer:整数 (Int32 Int64 你们就知道有个Int就行了,一般我
Neo4J之标签类型
Neo4J的标签可以理解一个类,在创建一个节点时可以设置一个或多个标签: **1\. 标签名为中文(可以)** ![](https://img2018.cnblogs.com/blog/1309692/201809/1309692-20180905104037922-144441266.png) ![](https://oscimg.oschina.n
Python 入门 之 类成员
Python 入门 之 类成员 =============== 1、类的私有成员: --------- ### 私有: 只能自己拥有 #### 以 \_\_ 开头就是私有内容 对于每一个类的成员而言都有两种形式: - 公有成员,在任何地方都能访问 - 私有成员,只有在类的内部才能使用 私有成员和公有