设计模式 - 六大设计原则之SRP(单一职责)

news2024/9/24 19:18:42

文章目录

  • 概述
  • Case
  • Bad Impl
  • Better Impl
    • 1. 定义接口
    • 2. 职责分离-多种实现类
    • 3. 单元测试
  • 小结

在这里插入图片描述


概述

单一职责原则(Single Responsibility Principle, SRP)又称单一功能原则,是面向对象的五个基本原则(SOLID)之一。 它规定一个类应该只有一个发生变化的原因。

在程序设计领域,SOLID 是由罗伯特·C·马丁在 21 世纪早期引入的记忆术首字母缩略字,指代了面向对象编程和面向对象设计的五个基本原则。当这些原则被一起应用时,能够使得一个程序员开发一个容易进行维护和扩展的系统变得更加可能。

SOLID 是以下五个单词的缩写:

Single Responsibility Principle(单一职责原则)

Open Closed Principle(开闭原则)
Liskov Substitution Principle(里氏替换原则)
Interface Segregation Principle(接口隔离原则)
Dependency Inversion Principle(依赖倒置原则)


我们设想一下: 加入需要开发的功能需求不是一次性的,且随着业务的发展而不断变化,那么当一个Class类负责的功能超过两个及以上职责时, 就在需求的不断迭代、实现类持续扩张的情况下,久而久之就会出现代码难以维护、扩展困难、测试难度大、上线风险高等诸多问题。

所谓的职责就是指类变化的原因,也就是业务需求。 如果一个类有多于一个的原因被改变,那么这个类就有超过两个及以上的职责。 而单一直接就是约定一个类应该有且仅有一个改变的原因。


Case

  • 访客用户, xxxx
  • 普通会员, xxxx
  • VIP会员, xxxx

Bad Impl

public class VideoUserService {

    public void serveGrade(String userType){
        if ("VIP用户".equals(userType)){
            System.out.println("VIP用户,视频1080P蓝光");
        } else if ("普通用户".equals(userType)){
            System.out.println("普通用户,视频720P超清");
        } else if ("访客用户".equals(userType)){
            System.out.println("访客用户,视频480P高清");
        }
    }

}

可以看到实现非常简单,暂时也不会出现什么问题。 但这一个类里包含多个不同的行为 ,也就是多种用户职责。 如果在这样的类上进行功能扩展或者逻辑修改,就会显得非常的臃肿。

接下来我们看看如何调用处理,写个单测

    @Test
    public void test_serveGrade(){
        VideoUserService service = new VideoUserService();
        service.serveGrade("VIP用户");
        service.serveGrade("普通用户");
        service.serveGrade("访客用户");
    }

在这里插入图片描述

因为上面的实现方式是在VideoUserService#serveGrade 通过if else实现的业务逻辑, 所以在调用方法是所有的职责用户都使用一个方法实现,作为程序的调用入口。

简单的需求没啥问题,频繁变化的需求带来的代码修改都有可能影响其他逻辑,给整个接口服务带来不可控的风险。

在这里插入图片描述


Better Impl

为了满足不断迭代的需求, 就不能使用一个类把所有的职责行为混为一谈,而是应该提供一个上层的接口,对不同的差异化的用户给出单独的实现类,拆分各自的职责边界。

1. 定义接口

public interface IVideoUserService {

    // 视频清晰级别;480P、720P、1080P
    void definition();

    // 广告播放方式;无广告、有广告
    void advertisement();

}

定义出上层接口IVideoUserService ,统一定义需要实现的功能: 视频清晰级别接口、广告播放方式接口 。 三种不同类型的用户就可以分别实现自己的服务类,做到职责统一。


2. 职责分离-多种实现类

【访问客户】

public class GuestVideoUserService implements IVideoUserService {
    
    public void definition() {
        System.out.println("访客用户,视频480P高清");
    }

    public void advertisement() {
        System.out.println("访客用户,视频有广告");
    }

}

【普通会员】

public class OrdinaryVideoUserService implements IVideoUserService {

    public void definition() {
        System.out.println("普通用户,视频720P超清");
    }

    public void advertisement() {
        System.out.println("普通用户,视频有广告");
    }

}

【VIP】

public class VipVideoUserService implements IVideoUserService {

    public void definition() {
        System.out.println("VIP用户,视频1080P蓝光");
    }

    public void advertisement() {
        System.out.println("VIP用户,视频无广告");
    }

}

综上,每种用户对应的服务职责都有各自的类负责实现,不会相互干扰。 当某一类需要添加新的运营规则时,操作起来也比较简单。


3. 单元测试

  @Test
    public void test_VideoUserService(){

        IVideoUserService guest = new GuestVideoUserService();
        guest.definition();
        guest.advertisement();

        IVideoUserService ordinary = new OrdinaryVideoUserService();
        ordinary.definition();
        ordinary.advertisement();

        IVideoUserService vip = new VipVideoUserService();
        vip.definition();
        vip.advertisement();

    }

可以看到,利用单一原则优化后,每个类都只负责自己的用户行为。 后续无论是扩展还是修改仅需要修改某个用户行为类即可。


小结

在项目开中,尽可能保证接口的定义、类的实现、方法开发保持单一的职责,对项目的迭代和维护非常有帮助 .

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022这一年

前言 一年过得好快啊,这个年终总结不知道该写点啥,所以一直到现在也没动笔。 但如果不写吧,总感觉少了点什么。就像过年守夜,反正我是每年都要等到凌晨12点放完鞭炮后才睡。 前些天也看到不少博主发布了2022年终总结,…

【ARM体系结构】之相关概念与公司简介

1、ARM相关的概念 机器码:计算机可以识别的0和1的组合。即高低电平的信号,1高电平信号,0低电平信号 汇编指令:编译器可以将汇编指令(存在代码段)编译成为机器码,执行汇编指令可以完成相应的汇编…

【进击的算法】基础算法——动态规划

🍿本文主题:动态规划 🎈更多算法:回溯算法 💕我的主页:蓝色学者的主页 文章目录一、前言二、概念2.1概念一:状态转移2.2概念二:Dp数组三、例题3.1斐波那契数列3.1.1题目描述3.1.2状态…

JQUERY总结(四)

对象拷贝&#xff1a; <script src"jQuery.min.js"></script> <script>$(function(){// var targetObj{};// var obj{// id:0,// name:"xinyi",// location:"henan"// };// //覆盖以前的相同key值对应的数据// $.…

【自然语言处理】基于NLP的电影评论情感分析模型比较

基于NLP的电影评论情感分析模型比较一段时间以来&#xff0c;使用机器学习的 NLP 任务借助 BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;模型被认为是当前的黄金标准。这些模型通常用于我们日常的许多语言处理任务&#xff0c;比如谷…

Java面试题,线程安全问题

线程安全问题一、对线程安全的理解&#xff08;实际上是内存安全&#xff09;二、Thread类的继承、Runable接口的重写三、守护线程四、ThreadLocal原理和使用场景五、sleep、wait、join、yield六、线程池、解释线程池参数一、对线程安全的理解&#xff08;实际上是内存安全&…

JVM面试一

5. JVM 5.1 JVM包含哪几部分? 参考答案 JVM 主要由四大部分组成:ClassLoader(类加载器),Runtime Data Area(运行时数据区,内存分区),Execution Engine(执行引擎),Native Interface(本地库接口),下图可以大致描述 JVM 的结构。 JVM 是执行 Java 程序的虚拟计算…

【计算机组成原理】第一章 计算机系统概述

文章目录第一章 知识体系1.1 计算机发展历程1.1.1 计算机硬件的发展1.1.2 计算机软件的发展1.2 计算机系统层次结构1.2.1 计算机系统的组成1.2.2 计算机硬件1.2.3 计算机软件1.2.4 计算机的层次结构1.2.5 计算机系统的工作原理1.3 计算机的性能指标第一章 知识体系 1.1 计算机发…

35.Isaac教程--机械臂取放物体示例应用程序

机械臂取放物体示例应用程序 ISAAC教程合集地址文章目录机械臂取放物体示例应用程序使用 Omniverse 套件模拟驱动的机器人手臂启动取放示例应用程序该包为拾取和放置场景提供了一个应用程序脚手架。 它具有执行拾取和放置任务所需的高级步骤&#xff0c;并与两种类型的机器人操…

Java面试题,Spring与SpringBoot相关问题

Spring与SpringBoot相关问题1、BeanFactory和ApplicationContext有什么区别&#xff1f;2、描述一下Spring Bean的生命周期3、Spring的几种Bean的作用域4、单例Bean是线程安全的吗&#xff1f;5、Spring框架用到了哪些设计模式6、Spring事务的实现方式、隔离级别、传播行为7、S…

Lesson4--栈和队列

目录 1.栈 1.1栈的概念及结构 1.2栈的实现 初始化栈 销毁栈 栈的扩容 入栈 出栈 获取栈顶元素 获取栈中有效元素个数 判空 程序代码如下 Stack.h Stack.c test.c 2.队列 2.1队列的概念及结构 ​2.2队列的实现 初始化队列 队尾入队列 队头出队列 获取队列头部元素 获取…

二、pyhon基础语法篇(黑马程序猿-python学习记录)

黑马程序猿的python学习视频&#xff1a;https://www.bilibili.com/video/BV1qW4y1a7fU/ 目录 一 、print 1. end 2. \t对齐 二、字面量 1. 字面量的含义 2. 常见的字面量类型 3. 如何基于print语句完成各类字面量的输出 三、 注释的分类 1. 单行注释 2. 多行注释 3. 注释的…

多进程|基于非阻塞调用的轮询检测方案|进程等待|重新理解挂起|Linux OS

说在前面 今天给大家带来操作系统中进程等待的概念&#xff0c;我们学习的操作系统是Linux操作系统。 我们今天主要的目标就是认识wait和waitpid这两个系统调用。 前言 那么这里博主先安利一下一些干货满满的专栏啦&#xff01; 手撕数据结构https://blog.csdn.net/yu_cbl…

nacos源码分析==服务订阅-服务端推送被订阅者最新信息给订阅者

上一篇讲到客户端发送请求到服务端进行服务注册&#xff0c;注册后&#xff0c;服务端会发出两个事件&#xff0c;第一个事件会触发另一个ServiceChangedEvent&#xff0c;这个事件被com.alibaba.nacos.naming.push.v2.NamingSubscriberServiceV2Impl#onEvent 监听&#xff0c…

16. 条件控制

总体来说&#xff0c;条件控制的效果类似c/c/c#/java中的&#xff0c;只不过在语法格式的层面上存在一定的差异。 1. if条件语法格式 if condition_1:...elif condition_2:...else:...1、python 中用 elif 代替了 c/c中的 else if&#xff0c;所以if语句的关键字为&#xff1a…

高性能排序函数实现方案

如C语言的qsort()、Java的Collections.sort()&#xff0c;这些排序函数如何实现&#xff1f; 1 合适的排序算法&#xff1f; 线性排序算法的时间复杂度较低&#xff0c;适用场景特殊&#xff0c;通用排序函数不能选择。 小规模数据排序&#xff0c;可选时间复杂度O(n^2)算法大…

【算法】滑动窗口

目录1.概述2.算法框架3.应用本文参考&#xff1a; LABULADONG 的算法网站 1.概述 &#xff08;1&#xff09;滑动窗口可以用以解决数组/字符串的子元素相关问题&#xff0c;并且可以将嵌套的循环问题&#xff0c;转换为单循环问题&#xff0c;从而降低时间复杂度。故滑动窗口算…

【数据分析】(task5)数据建模及模型评估

note 文章目录note一、建立模型二、模型评估2.1 交叉验证2.2 混淆矩阵/recall/accuracy/F12.3 ROC曲线三、Pyspark进行基础模型预测时间安排Reference一、建立模型 下载sklearn的命令pip install scikit-learn。 from sklearn.model_selection import train_test_split impor…

ARP渗透与攻防(二)之断网攻击

ARP断网攻击 系列文章 ARP渗透与攻防(一)之ARP原理 1.环境准备 kali 作为ARP攻击机&#xff0c;IP地址&#xff1a;192.168.110.26 MAC地址&#xff1a;00:0c:29:fc:66:46 win10 作为被攻击方&#xff0c;IP地址&#xff1a;192.168.110.12 MAC地址&#xff1a;1c:69:7a:a…

Tkinter的Entry与Text

Tkinter界面设计之输入控件Entry以及文本框控件Text。 目录 一、放置控件 1. pack()函数 2. place()函数 3. grid()函数 二、简单控件 1. Entry输入控件 1.1 tk.StringVar()函数&#xff1a;接收一个字符串 1.2 tk.Entry()函数&#xff1a;设置一个输入控件E 2. Text文…