整洁架构SOLID-单一职责原则(SRP)

文章目录

  • 定义
  • 案例分析
    • 重复的假象
    • 代码合并
    • 解决方案
  • 小结

定义

SRP是SOLID五大设计原则中最容易被误解的一个。也许是名字的原因,很多程序员根据SRP这个名字想当然地认为这个原则就是指:每个模块都应该只做一件事

在历史上,我们曾经这样描述SRP这一设计原则:

任何一个软件模块都应该有且仅有一个被修改的原因

在现实环境中,软件系统为了满足用户和所有者的要求,必然要经常做出这样那样的修改。而该系统的用户或者所有者就是该设计原则中所指的“被修改的原因”。所以,我们也可以这样描述SRP:

任何一个软件模块都应该只对一个用户(User)或系统利益相关者(Stakeholder)负责

不过,这里的“用户”和“系统利益相关者”在用词上也并不完全准确,它们很有可能指的是一个或多个用户和利益相关者,只要这些人希望对系统进行的变更是相似的,就可以归为一类——一个或多个有共同需求的人。在这里,我们将其称为行为者(actor)。

所以,对于SRP的最终描述就变成了:

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

案例分析

重复的假象

某个工资管理程序中的Employee类有三个函数calculatePay()、reportHours()和save()
在这里插入图片描述

如上图所示这个类的三个函数分别对应的是三类非常不同的行为者,违反了SRP设计原则。

  • calculatePay()函数是由财务部门制定的,他们负责向CFO汇报。
  • reportHours()函数是由人力资源部门制定并使用的,他们负责向COO汇报。
  • save()函数是由DBA制定的,他们负责向CTO汇报。

这三个函数被放在同一个源代码文件,即同一个Employee类中,程序员这样做实际上就等于使三类行为者的行为耦合在了一起,这有可能会导致CFO团队的命令影响到COO团队所依赖的功能

例如,calculatePay()函数和reportHours()函数使用同样的逻辑来计算正常工作时数。程序员为了避免重复编码,通常会将该算法单独实现为一个名为regularHours()的函数:
在这里插入图片描述

接下来,假设CFO团队需要修改正常工作时数的计算方法,而COO带领的HR团队不需要这个修改,因为他们对数据的用法是不同的。这时候,负责这项修改的程序员会注意到calculatePay()函数调用了regularHours()函数,但可能不会注意到该函数会同时被reportHours()调用。

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

代码合并

一个拥有很多函数的源代码文件必然会经历很多次代码合并,该文件中的这些函数分别服务不同行为者的情况就更常见了。

例如,CTO团队的DBA决定要对Employee数据库表结构进行简单修改。与此同时,COO团队的HR需要修改工作时数报表的格式。

这样一来,就很可能出现两个来自不同团队的程序员分别对Employee类进行修改的情况。不出意外的话,他们各自的修改一定会互相冲突,这就必须要进行代码合并

在这个例子中,这次代码合并不仅有可能让CTO和COO要求的功能出错,甚至连CFO原本正常的功能也可能受到影响。

多人为了不同的目的修改了同一份源代码,这很容易造成问题的产生。

解决方案

最简单直接的办法是将数据与函数分离,设计三个类共同使用一个不包括函数的、十分简单的EmployeeData类,每个类只包含与之相关的函数代码,互相不可见,这样就不存在互相依赖的情况了。
在这里插入图片描述

这种解决方案的坏处在于:程序员现在需要在程序里处理三个类。另一种解决办法是使用Facade设计模式:
在这里插入图片描述

这样一来,EmployeeFacade类所需要的代码量就很少了,它仅仅包含了初始化和调用三个具体实现类的函数。

我们也可以选择将最重要的函数保留在Employee类中,同时用这个类来调用其他没那么重要的函数:
在这里插入图片描述

总而言之,上面的每一个类都分别容纳了一组作用于相同作用域的函数,而在该作用域之外,它们各自的私有函数是互相不可见的。

小结

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

参考内容来源于:《架构整洁之道》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/781862.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSS技巧:纯CSS实现文字渐变动画效果

文字渐变动画&#xff0c;可以实现的有两种&#xff1a;一种是一行文字整体变化颜色&#xff1b;另一种一行文字依次变化颜色。接下来&#xff0c;我就介绍一下这两种文字渐变的实现过程。 布局代码&#xff1a; <div class"con"><div class"animate…

GPIO配置-PIN_Speed的理解

在使用STM32的GPIO 口配置时&#xff0c;经常会疑惑应该选用什么样的配置模式&#xff0c;本文谈谈对pin_speed的理解。 根据数据手册可得&#xff0c;STM32提供10MHz,2MHz和50MHz三种输出速度的配置&#xff0c;三种配置的应用场景是怎么样的&#xff1f;。 1.为什么要配置引…

力扣双指针算法题目:快乐数

目录 1.题目 2.思路解析 3.代码展示 1.题目 . - 力扣&#xff08;LeetCode&#xff09; 2.思路解析 题目意思是将一个正整数上面的每一位拿出来&#xff0c;然后分别求平方&#xff0c;最后将这些数字的平方求和得到一个数字&#xff0c;如此循环&#xff0c;如果在此循环中…

OpenEarthMap:全球高分辨率土地覆盖制图的基准数据集(开源来下载!!!)

OpenEarthMap由220万段5000张航拍和卫星图像组成&#xff0c;覆盖6大洲44个国家97个地区&#xff0c;在0.25-0.5m的地面采样距离上人工标注8类土地覆盖标签。我们提供8类标注:裸地、牧场、已开发空间、道路、树木、水、农业用地和建筑。类选择与现有的具有亚米GSD的产品和基准数…

C#知识|项目的实施过程及通用三级架构的搭建笔记

哈喽,你好啊,我是雷工! 01 项目需求分析 根据与需求方沟通,分析需求,一般都有需求分析师来进行项目需求收集与分析。 根据需求文档进行项目功能设计。 02 框架的选择 ①小项目可以根据需求选择两层或三层结构。 ②中型大型项目,至少需要三层架构和其他架构的组合。 03 框…

ESP32 步进电机精准控制:打造高精度 DIY 写字机器人,实现流畅书写体验

摘要: 想让你的 ESP32 不再仅仅是控制灯光的工具吗&#xff1f; 本文将带你使用 ESP32 开发板、步进电机和简单的机械结构打造一个能够自动写字的机器人。我们将深入浅出地讲解硬件连接、软件代码以及控制逻辑&#xff0c;并提供完整的项目代码和电路图&#xff0c;即使是 Ardu…

使用握手信号实现跨时钟域数据传输

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 参考代码 描述 分别编写一个数据发送模块和一个数据接收模块&#xff0c;模块的时钟信号分别为clk_a&#xff0c;clk_b。两个时钟的频率不相同。数据发送模块循环发送0-7&#xff0c;在每个数据传输完成之后&#xf…

六、数据可视化—首页、列表页制作(爬虫及数据可视化)

六、数据可视化—首页、列表页制作&#xff08;爬虫及数据可视化&#xff09; 1&#xff0c;首页制作&#xff08;1&#xff09;创建新项目选择flask框架&#xff08;2&#xff09;下载模板&#xff08;3&#xff09;导入flask框架中进行改写&#xff08;4&#xff09;访问服务…

puppeteer 爬虫初探

1. puppeteer 和 puppeteer-core 安装 puppeteer 会默认下载一个最新版本的 chrome 浏览器&#xff1b; 安装 puppeteer-core &#xff0c;不会安装 chrome, 若要程序打开浏览器运行时&#xff0c;需手动指定电脑系统安装的 chrome 浏览器路径&#xff1b; 2. puppeteer-core …

某大会的影响力正在扩大,吞噬了整个数据库世界!

1.规模空前 你是否曾被那句“上有天堂&#xff0c;下有苏杭”所打动&#xff0c;对杭州的湖光山色心驰神往&#xff1f;7月&#xff0c;正是夏意正浓的时节&#xff0c;也是游览杭州的最佳时期。这座古典与现代交融的城市将迎来了第13届PostgreSQL中国技术大会。作为全球数据库…

禁用windows的语音识别快捷键win+ctrl+s

win11组合键winctrls会弹出语音识别提示&#xff0c;即使到设置里禁用了语音识别也没用 解决办法&#xff1a;安装PowerToys&#xff0c;通过“键盘管理器”-“重新映射快捷键”禁用 PowerToys是微软自己的工具&#xff0c;不用担心安全问题&#xff0c;下载地址&#xff1a;h…

昇思25天学习打卡营第9天|静态图模式的深度剖析与应用指南

目录 背景介绍 动态图模式 静态图模式 静态图模式的使用场景 静态图模式开启方式 基于装饰器的开启方式 基于context的开启方式 静态图的语法约束 JitConfig配置选项 静态图高级编程技巧 背景介绍 AI 编译框架主要包含两种运行模式&#xff0c;即动态图模式与静态图模…

解决GPT-4o耗电难题!DeepMind新算法训练效率提升13倍,能耗降低10倍!

目录 01 有更好的解决方案吗&#xff1f; 02 从“超级batch”中筛选数据 03 技术介绍 04 实验结果 生成可学习batch 谷歌DeepMind推出的新算法JEST&#xff0c;将LLM训练的迭代次数减少了13倍&#xff0c;计算量降低了10倍&#xff0c;有望重塑AI未来。GPT-4o早已成为耗能…

python破解字母已知但大小写未知密码

python穷举已知字符串中某个或多个字符为大写的所有情况 可以使用递归函数来实现这个功能。以下是一个示例代码&#xff1a; def generate_uppercase_combinations(s, index0, current):if index len(s):print(current)returngenerate_uppercase_combinations(s, index 1, …

Debezium报错处理系列之第109篇:解决升级日志解析jar包重启集群出现的字段类型和值不匹配的错误

Debezium报错处理系列之第109篇:解决升级日志解析jar包重启集群出现的字段类型和值不匹配的错误 一、完整报错二、错误原因三、解决方法Debezium从入门到精通系列之:研究Debezium技术遇到的各种错误解决方法汇总: Debezium从入门到精通系列之:百篇系列文章汇总之研究Debezi…

Educational Codeforces Round 167 (Rated for Div. 2)(A~C)题解

A. Catch the Coin 解题思路: 最终&#x1d465;一定会相等&#xff0c;我们考虑直接到下面接住他。 #include<bits/stdc.h> using namespace std; typedef long long ll; #define N 1000005 ll dp[N], w[N], v[N], h[N]; ll dis[1005][1005]; ll a, b, c, n, m, t; ll…

【数据结构与算法】希尔排序

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注 ​

CH552G使用的pwm出现的问题,及设置

输出pwm的频率周期很不准确 可能是因为没有外部晶振的稳定晶振周期有关。 使用的示波器出现操作失误 在使用小型示波器的过程中发现集成了信号发生器和示波器的连接端口是不同的。刚开始把示波器测试口错插入了信号发生器的接口&#xff0c;困扰好一会儿&#xff0c;幸好用一…

人工智能、机器学习、神经网络、深度学习和卷积神经网络的概念和关系

人工智能&#xff08;Artificial Intelligence&#xff0c;缩写为AI&#xff09;--又称为机器智能&#xff0c;是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。 人工智能是智能学科重要的组成部分&#xff0c;它企图了解智能的实质…

浅谈进程隐藏技术

前言 在之前几篇文章已经学习了解了几种钩取的方法 浅谈调试模式钩取浅谈热补丁浅谈内联钩取原理与实现导入地址表钩取技术 这篇文章就利用钩取方式完成进程隐藏的效果。 进程遍历方法 在实现进程隐藏时&#xff0c;首先需要明确遍历进程的方法。 CreateToolhelp32Snapsh…