当前位置: 首页 > news >正文

单一职责原则

单一职责原则:

就一个类而言,应该只有一个引起它变化的原因,如果一个类承担的职责过多就等于把这些职责耦合在一起,至少会造成以下两方面的问题:

  • 我们要去修改该类中的一个职责可能会影响到该类的其它职责。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。
  • 当客户端仅需要该对象的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余代码或代码的浪费。

我们在设计一个类时要学会发现职责,并把那些职责相互分离,其实要去判断是否应该分离出一个类来并不难,前面说过,一个类应该只有一个引起它变化的原因,如果你能想到其它的原因也能去改变这个类,那么这个类就具有多于1个的职责,就应该考虑类的职责分离。

在之前的这篇博客中,https://blog.csdn.net/weixin_44049823/article/details/128907849,我们实现的计算器实际上也用到了单一职责原则,这里我们选出其中最经典的3.0版本和5.0版本来学习单一职责原则。

3.0版本计算器代码如下:

#include<iostream>
using namespace std;
#include<string>//业务逻辑
//异常类用于处理异常情况
class opeException
{
public:void getMessage(){cout << "您的输入有误!" << endl;}
};//运算类用于处理运算
class Operation
{
public:Operation(string& _num1, string& _num2, string& _ope) :num1(_num1), num2(_num2), ope(_ope){}//获取运算结果int getResult(){if (!(isStringNum(num1) && isStringNum(num2) && (ope == "+" || ope == "-" || ope == "*" || ope == "/")))throw opeException();if (ope == "+"){re = stoi(num1) + stoi(num2);}else if (ope == "-"){re = stoi(num1) - stoi(num2);}else if (ope == "*"){re = stoi(num1) * stoi(num2);}else if (ope == "/"){if (stoi(num2) != 0){re = stoi(num1) / stoi(num2);}elsethrow opeException();}return re;}
private:int re;string num1;string num2;string ope;//判断一个字符串是不是数字bool isStringNum(string& s){bool flag = true;for (auto e : s)if (!(isdigit(e))){flag = false;break;}return flag;}
};//界面逻辑
int main()
{try{string _num1 = " ";string _num2 = " ";string _ope = " ";cout << "请输入左操作数:" << endl;cin >> _num1;cout << "请输入右操作数:" << endl;cin >> _num2;cout << "请输入操作符" << endl;cin >> _ope;Operation operation(_num1, _num2, _ope);cout << operation.getResult() << endl;}catch (opeException &ex){ex.getMessage();}return 0;
}

仅仅一个运算类Operation就实现了加减乘除4种功能,很明显在这个类中我至少有4个原因去修改这个类,我修改加法算法的时候可能会影响到其它的运算算法,这个类的耦合太高且严重违反了单一职责原则。

修改后的5.0版本如下:

#include<iostream>
using namespace std;
#include<string>//业务逻辑//异常类用于处理异常情况
class opeException
{
public:void getMessage(){cout << "您的输入有误!" << endl;}
};//运算类
class Operation
{//判断一个字符串是不是数字bool isStringNum(string& s){bool flag = true;for (auto e : s)if (!(isdigit(e))){flag = false;break;}return flag;}protected:bool isError(string& _strNum1, string& _strNum2, string& _ope){if (!(Operation::isStringNum(_strNum1) && Operation::isStringNum(_strNum2) && (_ope == "+" || _ope == "-" || _ope == "*" || _ope == "/"))){return false;}}
public:virtual int getResult() = 0;
};//加法运算类
class addOperation :public Operation
{
private:string strNum1;string strNum2;string ope;int re;
public:addOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {}virtual int getResult() override{if (!isError(strNum1, strNum2, ope))throw opeException();elsere = stoi(strNum1) + stoi(strNum2);return re;}
};//减法运算类
class subOperation :public Operation
{
private:string strNum1;string strNum2;string ope;int re;
public:subOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {}virtual int getResult() override{if (!isError(strNum1, strNum2, ope))throw opeException();elsere = stoi(strNum1) - stoi(strNum2);return re;}
};//乘法运算类
class mulOperation :public Operation
{
private:string strNum1;string strNum2;string ope;int re;
public:mulOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {}virtual int getResult() override{if (!isError(strNum1, strNum2, ope))throw opeException();elsere = stoi(strNum1) * stoi(strNum2);return re;}
};//除法运算类
class divOperation :public Operation
{
private:string strNum1;string strNum2;string ope;int re;
public:divOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {}virtual int getResult() override{if (!isError(strNum1, strNum2, ope))throw opeException();else if (stoi(strNum2) != 0)re = stoi(strNum1) / stoi(strNum2);elsethrow opeException();return re;}
};//运算工厂类
class OpeFactory
{
public:Operation& choose(string &_strNum1,string &_strNum2,string &_ope){if (_ope == "+"){operation = new addOperation(_strNum1, _strNum2, _ope);}else if (_ope == "-")operation = new subOperation(_strNum1, _strNum2, _ope);else if (_ope == "*")operation = new mulOperation(_strNum1, _strNum2, _ope);else if (_ope == "/"){operation = new divOperation(_strNum1, _strNum2, _ope);}elseoperation = nullptr;return *operation;}private:Operation* operation;
};//界面逻辑
int main()
{try{string _strNum1 = " ";string _strNum2 = " ";string _ope = " ";cout << "请输入左操作数:" << endl;cin >> _strNum1;cout << "请输入右操作数:" << endl;cin >> _strNum2;cout << "请输入操作符:" << endl;cin >> _ope;OpeFactory factory;Operation* re = &factory.choose(_strNum1, _strNum2, _ope);if (re != nullptr)cout << (*re).getResult() << endl;elsecout << "您的输入有误!" << endl;}catch (opeException ex){cout << "您的输入有误" << endl;}return 0;
}

在5.0版本的计算器代码中,我们将运算类分成了4种类,分别是加法类、减法类、乘法类、除法类,还创建了一个工厂类专门用于根据不同情况实例化对象,每个类只有一个职责,我们要修改某个功能只需要去修改对应的类即可,极大降低了代码之间的耦合。

单一职责原则的核心就是控制类的粒度大小、将对象解耦、提高其内聚性。如果遵循单一职责原则将有以下优点:

  • 降低类的复杂度。一个类只负责一项职责,其逻辑肯定要比负责多项职责简单得多。
  • 提高类的可读性。复杂性降低,自然其可读性会提高。
  • 提高系统的可维护性。可读性提高,那自然更容易维护了。
  • 变更引起的风险降低。变更是必然的,如果单一职责原则遵守得好,当修改一个功能时,可以显著降低对其他功能的影响。

相关文章:

单一职责原则

单一职责原则&#xff1a; 就一个类而言&#xff0c;应该只有一个引起它变化的原因&#xff0c;如果一个类承担的职责过多就等于把这些职责耦合在一起&#xff0c;至少会造成以下两方面的问题&#xff1a; 我们要去修改该类中的一个职责可能会影响到该类的其它职责。这种耦合…...

golangの并发编程(GMP模型)

GMP模型 && channel1. 前言2. GMP模型2.1. 基本概念2.2. 调度器策略2.3. go指令的调度流程2.4. go启动周期的M0和G02.5. GMP可视化2.6. GMP的几种调度场景3. channel3.1. channel的基本使用3.2. 同步器1. 前言 Go中的并发是函数相互独立运行的体现&#xff0c;Gorouti…...

MacBook Pro错误zsh: command not found: brew解决方法

问题描述&#xff1a;本地想安装Jenkins&#xff0c;但是brew指令不存在/我的电脑型号是19款的MacBook Pro&#xff08;Intel芯片&#xff09;。解决方法MacBook Pro 重新安装homebrew&#xff0c;用以下命令安装&#xff0c;序列号选择阿里巴巴下载源。/bin/zsh -c "$(cu…...

spring中BeanFactory 和ApplicationContext

在学习spring的高阶内容时&#xff0c;我们有必要先回顾一下spring回顾spring1.什么是springspring是轻量级的&#xff0c;指核心jar包时很小的&#xff1b;非侵入式的一站式框架(数据持久层&#xff0c;web层&#xff0c;核心aop)&#xff0c;为了简化企业级开发。核心是IOC&a…...

HC32L17x的LL驱动库之dma

#include "hc32l1xx_ll_dma.h"/// //函 数: //功 能: //输入参数: //输出参数: //说 明: // uint8_t LL_DMA_DeInit(DMA_TypeDef* DMAx, uint32_t Channel) {__IO uint32_t* dmac NULL;dmac &(DMAx->CONFA0);Channel << 4;dmac …...

SSM项目 替换为 SpringBoot

一、运行SSM项目 保证项目改为SpringBoot后运行正常&#xff0c;先保证SSM下运行正常。 项目目录结构 创建数据库&#xff0c;导入sql文件 查看项目中连接数据jar版本&#xff0c;修改对应版本&#xff0c;修改数据库配置信息 配置启动tomcat 运行项目&#xff0c;测试正常…...

RL笔记:动态规划(2): 策略迭代

目录 0. 前言 (4.3) 策略迭代 Example 4.2: Jack’s Car Rental Exercise 4.4 Exercise 4.5 Exercise 4.6 Exercise 4.7 0. 前言 Sutton-book第4章&#xff08;动态规划&#xff09;学习笔记。本文是关于其中4.2节&#xff08;策略迭代&#xff09;。 (4.3) 策略迭代 基…...

2023软件测试金三银四常见的软件测试面试题-【测试理论篇】

三、测试理论 3.1 你们原来项目的测试流程是怎么样的? 我们的测试流程主要有三个阶段&#xff1a;需求了解分析、测试准备、测试执行。 1、需求了解分析阶段 我们的SE会把需求文档给我们自己先去了解一到两天这样&#xff0c;之后我们会有一个需求澄清会议&#xff0c; 我…...

蓝桥训练第二周

1 &#xff0c;泛凯撒加密 内存限制&#xff1a;128 MB时间限制&#xff1a;1.000 S 题目描述 众所周知&#xff0c;在网络安全中分为明文和密文&#xff0c;凯撒加密是将一篇明文中所有的英文字母都向后移动三位&#xff08;Z的下一位是A&#xff09;&#xff0c;比如a向后…...

详讲函数知识

目录 1. 函数是什么&#xff1f; 2. C语言中函数的分类&#xff1a; 2.1 库函数&#xff1a; 2.2 自定义函数 函数的基本组成&#xff1a; 3. 函数的参数 3.1 实际参数&#xff08;实参&#xff09;&#xff1a; 3.2 形式参数&#xff08;形参&#xff09;&#xff1a; …...

gin 框架初始教程文档

一 、gin 入门1. 安装gin &#xff1a;下载并安装 gin包&#xff1a;$ go get -u github.com/gin-gonic/gin2. 将 gin 引入到代码中&#xff1a;import "github.com/gin-gonic/gin"3.初始化项目go mod init gin4.完整代码package mainimport "github.com/gin-go…...

Maven的下载和安装【详细】

文章目录一、什么是Maven&#xff1f;二、Maven的安装与配置2.1下载Maven安装包2.2配置Maven环境变量2.3验证三、Idea配置Maven3.1配置 setting.xml文件3.2Idea配置Maven一、什么是Maven&#xff1f; Apache Maven是个项目管理和自动构建工具&#xff0c;基于项目对象模型&…...

[数据结构]:04-循环队列(数组)(C语言实现)

目录 前言 已完成内容 循环队列实现 01-开发环境 02-文件布局 03-代码 01-主函数 02-头文件 03-QueueCommon.cpp 04-QueueFunction.cpp 结语 前言 此专栏包含408考研数据结构全部内容&#xff0c;除其中使用到C引用外&#xff0c;全为C语言代码。使用C引用主要是为了…...

buu [GWCTF 2019]BabyRSA 1

题目描述&#xff1a; import hashlib import sympy from Crypto.Util.number import *flag GWHT{******} secret ******assert(len(flag) 38)half len(flag) / 2flag1 flag[:half] flag2 flag[half:]secret_num getPrime(1024) * bytes_to_long(secret)p sympy.nextp…...

codeforces 1669F

题意: alice和bob从数组两边的吃糖果, 数组的值就是糖果重量 要求alice和bob吃的糖果重量必须一样, 输出能吃几个糖果 这题最先想到的是前后缀相加 模拟一个前缀和 和 后缀和 在n/2的位置向前找前缀和 在n/2的位置向后找后缀和 找到第一个前缀和后缀和的下标输出就好 …...

高数考试必备知识点

三角函数与反三角函数的知识点 正弦函数 ysin x&#xff0c; 反正弦函数 yarcsin x • y sin x&#xff0c; x∈R&#xff0c; y∈[–1&#xff0c;1]&#xff0c;周期为2π&#xff0c;函数图像以 x (π/2) kπ 为对称轴 • y arcsin x&#xff0c; x∈[–1&#xff0c;1]…...

[蓝桥杯] 二分与前缀和习题练习

文章目录 一、二分查找习题练习 1、1 数的范围 1、1、1 题目描述 1、1、2 题解关键思路与解答 1、2 机器人跳跃问题 1、2、1 题目描述 1、2、2 题解关键思路与解答 1、3 四平方和 1、3、1 题目描述 1、3、2 题解关键思路与解答 二、前缀和习题练习 2、1 前缀和 2、1、1 题目描述…...

SpringMvc中HandlerAdapter组件的作用

概述 我们在使用springMVC时&#xff0c;都知道其中不仅包含handlerMapping组件还包含handlerAdapter组件&#xff0c;为什么呢&#xff1f; springMVC请求流程图 HandlerAdapter组件使用了适配器模式 适配器模式的本质是接口转换和代码复用&#xff0c;这里使用适配器模式的…...

FreeRTOS优先级翻转

优先级翻转优先级翻转&#xff1a;高优先级的任务反而慢执行&#xff0c;低优先级的任务反而优先执行优先级翻转在抢占式内核中是非常常见的&#xff0c;但是在实时操作系统中是不允许出现优先级翻转的&#xff0c;因为优先级翻转会破坏任务的预期顺序&#xff0c;可能会导致未…...

服务器部署—部署springboot之Linux服务器安装jdk和tomcat【建议收藏】

我是用的xshell连接的云服务器&#xff0c;今天想在服务器上面部署一个前后端分离【springbootvue】项目&#xff0c;打开我的云服务器才发现&#xff0c;过期了&#xff0c;然后又买了一个&#xff0c;里面环境啥都没有&#xff0c;正好出一期教程&#xff0c;方便大家也方便自…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

PAN/FPN

import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...