单一职责原则(Single Pesponsibility Principle, SRP)是SOLID五大设计原则最容易被误解的一个。也许是名字的原因,很多程序员根据SRP这个名字想当然地认为这个原则是指:每个模块应该只做一件事。但这只是一个面向底层实现细节的设计原则,并不是SRP的全部。对于SRP的描述是:

任何一个软件模块都应该只对某一类行为者负责。

大部分情况下,对于 “软件模块” 的简单定义就是一个源代码文件(如.java文件和.py文件等),也可以指一组紧密相关的函数和数据结构。对于 “行为者” 可以是该模块的用户和利益相关者,只要是这些人对系统进行的变更是相似的,都可以归为同一类行为者。如何去理解SRP这一原则,下面通过两个反面案例来详细说明。

反面案例1:重复的假象

有一个员工管理模块Employee类,Employee类有三个函数:calculatePay(),reportHours()和save()。如图:

这三个函数分别对应的是三类不同的行为者,违反了SRP设计原则。

  • calculatePay()是计算工资函数:由财务部门制定,负责向CFO(首席财务官)汇报。

  • reportHours()是日常运营报告函数:由人力资源部门制定,负责向COO(首席营运官)汇报。

  • save()是持久化数据函数:由DBA制定,负责向CTO(首席技术官)汇报。

这三个函数被放在同一个源文件中,即同一个Employee类中,这样做实际上就等于使三类行为者的行为耦合在了一起,这有可能会导致CFO团队的需求变更影响到COO团队所依赖的功能。例如,calculatePay()函数和reportHours()函数使用了同样逻辑来计算员工的工时情况。开发者为了避免重复代码,通常会将该算法单独实现为一个名为regularHours()的函数。

那么,假设CFO团队需要修改工时的计算方法,而COO团队不需要这个修改,因为他们对工时的计算方法可能存在差异。这时,负责修改代码的开发者会注意到calculatePay()函数调用了regularHours()函数,当可能不会注意到该函数同时被reportHours()函数调用。

于是,该开发者就这样按照需求修改了工时的计算方法,同时CFO团队也验证了新算法可以正常工作。这项修改最终被成功部署上线了。但是,COO团队显然不知道这些变更事情的发生,在他们继续使用regularHours()产生报表时,随后就会发现数据错误的结果。

这类问题发生的根源就是因为我们将不同行为者所依赖的代码强凑合到了一起,对此,SRP强调这类代码一定要分开。

反面案例2:代码合并

一个拥有很多函数的源代码文件必然会经历很多次代码合并,如果这些函数分别服务于不同的行为者,会给代码合并带来很多问题(如代码冲突、功能影响),虽然有svn和git代码托管工具,但是合并带来的问题还是不能得到有效解决。

例如,CTO团体的DBA决定要对Employee数据库表结构进行修改,与此同时,COO团队的HR需要修改员工工时报表的格式。这样,就很可能出现来自不同团队的开发者分别对Employee类进行修改的情况,导致各自的修改互相冲突,这就必须要进行代码合并。该例子中,这次代码合并不仅有可能让CTO和COO各自要求的功能出错,甚至连CFO原本正常的功能也可能受到影响。

这样的案例有很多,它们的一个共同点是,多人为了不同的目的修改了同一份源代码,这很容易造成问题的产生,而避免这种问题产生的方法就是将服务不同行为者的代码进行切分。

解决方案

我们有很多方法可以解决上面例子中的问题,每一种方法都需要将相关的函数划分成不同的类。

1. 方法一

最简单直接的方法是将数据和函数分离。设计三个函数类共同使用一个数据类EmployeeData,每个函数类只包含与之行为者相关函数代码,这样就不存在互相依赖的情况了。如图:

这种方案的缺点在于:开发者需要在程序里处理三个函数类。

1. 方法二

在方法一的基础上,使用Facade设计模式(外观设计模式),把三个函数类中需要对外使用到的函数合并到一个Facade类中。如图:

Facade设计模式的好处是:EmployeeFacade类的代码量较少,它仅仅包含了初始化和调用三个具体实现类的函数。

当然,也有些开发者更倾向于把最重要的业务逻辑和数据放在一起。对于上面例子,我们可以选择将最重要的函数保留在Employee类中,同时用这个类来调用其它没那么重要的函数。如图:

为了清晰的了解这些解决方案,每个函数类中都只有一个函数,事实上并非如此,因为计算工资、生成报表和持久化数据都比较复杂的过程,每个函数类都可能包含了许多私有函数。总而言之,上面的每一个类都分别容纳了一组作用于相同作用域的函数,且每个作用域各自的私有函数是互相不可见的。

总结

单一职责原则主要讨论的是函数和类之间的关系——但是该原则在两个不同层面上会以不同的形式出现。在组件层面,可以将其称为共同闭包原则(Common Closure Principle),在软件架构层面,它是用于奠定架构边界的变更轴心(Axis of Change)。这两个原则会在后续的文章中深入讨论。

软件架构-单一职责原则相关推荐

  1. 【软件架构设计原则】单一职责原则和接口隔离原则

    文章目录 软件架构设计原则 单一职责原则 接口隔离原则 其他设计原则 软件架构设计原则 本文通过实例来讲解 单一职责原则 接口隔离原则 单一职责原则 单一职责(Simple Responsibilit ...

  2. 前端中会用到的设计模式之单一职责原则

    1:设计模式应用不应用,取决于对现在和未来判断后的取舍.没必要用尽量不用! 2.设计模式的目的是  减少复杂度(一个函数中包含的功能个数), 降低耦合度(一个对象与其他对象的关系个数).耦合度不能为0 ...

  3. 学习设计模式 - 六大基本原则之单一职责原则

    设计模式总共有六大基本原则,统称为SOLID (稳定)原则,分别是S-单一职责原则(Single Responsibility Principle), O-开闭原则(Open closed Princ ...

  4. 设计模式原则--单一职责原则

    单一职责原则(SRP) 定义:就一个类而言,应该仅有一个引起它变化的原因 场景: 一个公司有3类员工,分别是 主管,程序员,销售 代码: using System; using System.Coll ...

  5. 北风设计模式课程---单一职责原则

    北风设计模式课程---单一职责原则 一.总结 一句话总结: 视频教程网上一定能找到做好笔记的博客,很大几率都不需要自己做笔记.比如北风设计模式课程,https://www.cnblogs.com/xi ...

  6. 设计模式 之 设计的 六大原则(1)单一职责原则

    由于这些原则性东西 属于概念东西,就不具体以代码描述了.以下是摘自网上和自己的一些理解 首先了解一些 面向对象的特性: 面向对象 有 三大基本特征:封装 ,继承, 多态. 封装: 也就是把客观事物封装 ...

  7. 1.单一职责原则(Single Responsibility Principle)

    1.定义 就一个类而言,应该仅有一个引起它变化的原因. 2.定义解读 这是六大原则中最简单的一种,通俗点说,就是不存在多个原因使得一个类发生变化,也就是一个类只负责一种职责的工作. 3.优点 类的复杂 ...

  8. 单一职责原则(SRP)

    单一职责原则(Single Pesponsibility Principle, SRP) 单一职责有两个含义: 一个是避免相同的职责分散到不同的类中, 别一个是避免一个类承担太多职责 为什么要遵守SR ...

  9. 【设计模式】单一职责原则

    单一职责原则 原则概述:一个类或者一个方法只负责一项职责或功能.如[类A]负责两个不同职责,即[职责1]和[职责2].当[职责1]需求变更而改变[类A]时,可能引用[类A对象]的[职责2]时执行错误, ...

最新文章

  1. ANSI编码和标准代码页(code page)
  2. 信息系统项目管理师优秀论文:项目采购管理
  3. 【操作】Json取value时,为什么得到的是undefined?
  4. Spark 编程模型(上)
  5. python字符串怎么用_零基础如何使用python处理字符串?
  6. mysql 主从热备份 5.6 参数_MySQL主从热备份
  7. python seek_Python 文件操作seek()函数
  8. python字符串转成数组_python将字符串转换成数组的方法
  9. O_NONBLOCK与O_NDELAY有何不同?
  10. 虚拟现实(VR)技术的升级应用|时空克隆 三维视频融合 投影融合 点卯 魔镜系列
  11. 前端实现简单的loding效果
  12. 赛效:如何在线更改图片格式 图片格式在线转换方法介绍
  13. 苹果手机白屏_安卓用久了卡顿 苹果用久了闪退 究竟是因为啥?
  14. java编译后的扩展名,Java源程序的扩展名是( ),经过编译后的程序的扩展名是( )...
  15. [千峰安全篇9]Public Key Infrastructure
  16. FreeRTOS 任务简介
  17. 2022电大国家开放大学网上形考任务-简明创新方法非免费(非答案)
  18. 如何在Linux虚拟器里新建跟目录,虚拟机linux 6 增加根目录
  19. 文件服务器维修,中国直辖市服务器维修及数据恢复.docx
  20. 模拟ARP欺骗攻击与防护

热门文章

  1. 利用IDL计算植被覆盖度(VFC)
  2. 人工智能:新时代的必修课
  3. 绝对让你眼前一亮的5款Revit渲染插件工具
  4. 湖北省科技企业孵化器和众创空间申报奖励补贴标准,2022年认定条件汇总
  5. 搭建nfs服务端和客户端
  6. viso 2003 windows 10 Microsoft Office 启动报错:无法验证产品的许可证
  7. 江苏省计算机c语言等级考试试题,2012江苏省计算机等级考试c语言试题答案.doc...
  8. 工信部就骚扰电话管控不力问题约谈中国电信
  9. 【原】S1普版加强版 完美仿钻石ROM
  10. 你看不见我眼中的泪,因为我在水中.我能感觉得到你的泪,因为你在我心中