贯穿设计模式第一话--单一职责原则

news2025/2/26 3:36:46

🥳🥳🥳 茫茫人海千千万万,感谢这一刻你看到了我的文章,感谢观赏,大家好呀,我是最爱吃鱼罐头,大家可以叫鱼罐头呦~🥳🥳🥳

在这里插入图片描述

从今天开始,将开启一个专栏,【贯穿设计模式】,设计模式是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。为了能更好的设计出优雅的代码,为了能更好的提升自己的编程水准,为了能够更好的理解诸多技术的底层源码, 设计模式就是基石,万丈高楼平地起,一砖一瓦皆根基。 ✨✨欢迎订阅本专栏✨✨

🥺 本人不才,如果文章知识点有缺漏、错误的地方 🧐,也欢迎各位人才们评论批评指正!和大家一起学习,一起进步! 👀

❤️ 愿自己还有你在未来的日子,保持学习,保持进步,保持热爱,奔赴山海! ❤️

💬 最后,希望我的这篇文章能对你的有所帮助! 🍊 点赞 👍 收藏 ⭐留言 📝 都是我最大的动力!

⛹🏼 设计模式的七大原则

🤔 为了能够更好的进入到设计模式的学习过程中,在设计程序的过程中,我们应当遵守以下原则,这也是各种设计模式的基础(即:设计模式为什么这样设计的依据)

  • 单一职责原则
  • 开闭原则
  • 依赖倒转原则
  • 里氏替换原则
  • 接口隔离原则
  • 迪米特法则
  • 合成复用原则

img

🏋🏼‍♀️单一职责原则

今天我们首先学习的是单一职责原则,一个类应该只有一个职责。

🤾🏼概述

  • 该原则是指对一个类来说,应当只有一个引起它变化的原因,否则类应该被拆分,即一个类应该只有一个职责,其中的职责表示引起该类变化的原因。
  • 简单理解为一个类应该只负责一项职责,这就是所谓的单一职责原则。
  • 如一个A类它负责多个职责,那么应该将A类拆分为多个类,将类的负责的职责力度细分,拆分为A1、A2、A3类等等来分别执行某一个职责。
  • 在我们编写代码的过程中,总会一些需求功能的变更,而我们也会很顺手的在每个类上加上各种各样的功能。这样意味着,无论任何需求要来,你都需要更改这个类,这样其实是很糟糕的,维护麻烦,复用不可能,也缺乏灵活性。如果一个类承担的职责过多,就等于把这些职责耦合起来,一个职责变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭到很多意想不到的破坏。所以我们在对于一个复杂的功能实现中,也可以利用这种思想,将这个复杂功能进行细粒度拆分,逐个完成拆分后的任务,这样开发和设计起来更加高效,更不容易出错。

🤹🏼‍♀️特点

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

  • 降低类的复杂度。一个类只负责一项职责,其逻辑肯定要比负责多项职责简单得多;
  • 提高类的可读性和可维护性。复杂性降低,相对可读性和可维护性都会提高;
  • 变更引起的风险降低。变更是必然的,如果单一职责原则遵守得好,当修改一个功能时,可以显著降低对其他功能的影响。
  • 通常情况下,我们应当遵守单一职责原则,只有逻辑足够简单,才可以在代码级违反单一职责原则;只有类中方法数量足够少,可以在方法级别保持单一职责原则

🤸🏼‍♀️问题引出

img

在学生时代上学时候中,我们都知道学生最主要就是来听讲老师上课的,接下来我们就一个学生上课的例子来讲解一番,先看以下代码:

package com.ygt.principle.single;

public class SingleResponsibility {

    public static void main(String[] args) {
        // 这里创建出来学生类
        Student student = new Student();

        // 学生中都会有一个功能,认真听讲上课
        // 分别创建张三和李四去认真听讲上课
        student.attendClass("张三");
        student.attendClass("李四");
    }
}

// 学生类
class Student {
    // 上课方法
    public void attendClass(String student) {
        System.out.println(student + " 正在认真听讲老师的内容上课!");
    }
}

上面代码运行结果为:

张三 正在认真听讲老师的内容上课!
李四 正在认真听讲老师的内容上课!

可事实上,你会发现在学校中,总不可能所有的学生都是会认真上课的,也是有分好学生或者坏学生的吧,好学生都会认真上课,坏学生总是在上课时候打瞌睡,那以我们现在的代码,貌似完成不了这种需求,现在的attendClass上课方法中,如果也负责坏学生上课的方法的话,就会导致违反了单一职责原则。接下来就看下上面的出现的问题如何解决。

🚵🏼‍♂️解决方案

解决方案1:

这里将学生类拆分为好学生类和坏学生类。

好学生类的上课方式是认真听讲上课,而坏学生类则是上课睡觉。

package com.ygt.principle.single;

public class SingleResponsibility2 {
    public static void main(String[] args) {
        // 这里创建出来两个学生类,分别好好学生和坏学生
        GoodStudent goodStudent = new GoodStudent();
        BadStudent badStudent = new BadStudent();

        // 好学生中认真听讲上课,分别创建张三和李四去认真听讲上课
        goodStudent.attendClass("张三");
        goodStudent.attendClass("李四");

        // 坏学生中就不会认真听讲上课,只会上课睡觉,创建赵六这个老六去睡觉
        badStudent.attendClass("赵六");
    }
}

// 好学生类
class GoodStudent {
    // 上课方法
    public void attendClass(String student) {
        System.out.println(student + " 正在认真听讲老师的内容上课!");
    }
}

// 坏学生类
class BadStudent {
    // 上课方法
    public void attendClass(String student) {
        System.out.println(student + " 正在听讲老师的催眠曲睡大觉~~~");
    }
}

上面代码运行结果为:

张三 正在认真听讲老师的内容上课!
李四 正在认真听讲老师的内容上课!
赵六 正在听讲老师的催眠曲睡大觉~~~

可是我们会发现如果这样修改花销是很大的,除了将原来的类分解之外,还需要修改main方法中代码。并且,如果又多一种其他类型的学生的话,类又需要重新拆分,main方法中的代码又得重新改一遍,所以这样虽然遵守了单一职责原则,但其实是不可取的。接下来就看下上面的出现的问题如何解决。

解决方案2:

这里就不拆分学生类了,而是将其中的上课方法进行拆分,拆分为好学生上课的方法和坏学生上课的方法。

package com.ygt.principle.single;

public class SingleResponsibility3 {

    public static void main(String[] args) {
        // 这里创建出来学生类
        Student2 student = new Student2();

        // 调用好学生方法去执行认真听讲上课
        student.goodAttendClass("张三");
        student.goodAttendClass("李四");

        // 调用坏学生方法去执行认真睡觉
        student.badAttendClass("赵六");

    }
}

// 学生类
class Student2 {
    // 好学生上课方法
    public void goodAttendClass(String student) {
        System.out.println(student + " 正在认真听讲老师的内容上课!");
    }

    // 坏学生上课方法
    public void badAttendClass(String student) {
        System.out.println(student + " 正在听讲老师的催眠曲睡大觉~");
    }
}

上面代码运行结果为:

张三 正在认真听讲老师的内容上课!
李四 正在认真听讲老师的内容上课!
赵六 正在听讲老师的催眠曲睡大觉~

可以看到,这种修改方式没有对类进行一个改动,反而是在类中新加了一个方法,这样虽然也违背了单一职责原则,但在方法级别上却是符合单一职责原则的,这也体现了只负责一项职责的功能,并且对于的代码的改动相对会比较少。

这三种方式各有优缺点,那么在实际编程中,采用哪一中呢?其实这真的比较难说,需要根据实际情况来确定。我的原则是:只有逻辑足够简单,才可以在代码级别上违反单一职责原则;只有类中方法数量足够少,才可以在方法级别上违反单一职责原则;

🌸 完结

相信各位看官看到这里大致都对设计模式中的其中一个原则有了了解吧,单一职责原则实际上的定义就是一个类应该只负责一项职责,以此控制类的粒度大小、将对象解耦、提高其内聚性。

学好设计模式,让你感受一些机械化代码之外的程序设计魅力,也可以让你理解各个框架底层的实现原理。最后,祝大家跟自己能在程序员这条越走越远呀,祝大家人均架构师,我也在努力。接下来期待第二话:开闭原则。 💪💪💪

文章的最后来个小小的思维导图:

🧐 本人不才,如有什么缺漏、错误的地方,也欢迎各位人才们评论批评指正!🤞🤞🤞

🤩 当然如果这篇文章确定对你有点小小帮助的话,也请亲切可爱的人才们给个点赞、收藏下吧,非常感谢!🤗🤗🤗

img

🥂 虽然这篇文章完结了,但是我还在,永不完结。我会努力保持写文章。来日方长,何惧车遥马慢!✨✨✨

💟 感谢各位看到这里!愿你韶华不负,青春无悔!让我们一起加油吧! 🌼🌼🌼

💖 学到这里,今天的世界打烊了,晚安!🌙🌙🌙

img

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

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

相关文章

基于51单片机的智能婴儿看护床设计

需要源码及原理图文件请私信!!!! 基于51单片机的智能婴儿看护床设计1、引言2、功能设计系统结构框图3、系统硬件设计3.1声音电路的设计3.2语音播报电路的设计3.3独立按键电路的设计3.4模拟摇床(步进电机驱动电路&#…

Springboot项目快速实现过滤器功能

前言很多时候,当你以为掌握了事实真相的时间,如果你能再深入一点,你可能会发现另外一些真相。比如面向切面编程的最佳编程实践是AOP,AOP的主要作用就是可以定义切入点,并在切入点纵向织入一些额外的统一操作&#xff0…

尚硅谷大数据技术Spark教程-笔记01【Spark(概述、快速上手、运行环境、运行架构)】

视频地址:尚硅谷大数据Spark教程从入门到精通_哔哩哔哩_bilibili 尚硅谷大数据技术Spark教程-笔记01【Spark(概述、快速上手、运行环境、运行架构)】尚硅谷大数据技术Spark教程-笔记02【SparkCore(核心编程、案例实操)】尚硅谷大数据技术Spark教程-笔记03【SparkSQL…

Scala之面向对象(2)

目录 单例对象(伴生对象): 创建对象常用的两种方法: (1)使用构造器构造(new) (2)使用静态方法 伴生对象的定义: apply方法: app…

图像分割技术及经典实例分割网络Mask R-CNN(含基于Keras Python源码定义)

图像分割技术及经典实例分割网络Mask R-CNN(含Python源码定义) 文章目录图像分割技术及经典实例分割网络Mask R-CNN(含Python源码定义)1. 图像分割技术概述2. FCN与语义分割2.1 FCN简介2.2 反卷积2.2 FCN与语义分割的关系3. Mask …

Midjourney以图生图的详细教程(含6种案例介绍)

🏆 文章目标:学习并介绍Midjourney以图生图的详细教程 🍀 Midjourney以图生图的详细教程 ✅ 创作者:熊猫Jay 🎉 个人主页:Jay的个人主页 🍁 展望:若本篇讲解内容帮助到您&#xff0c…

SQL Server 单表数据查询

提示: 本篇文章详细介绍怎样向SQLServer中导入表格数据,导入之后根据不同的查询条件完成查询任务. 文章目录前言一、向SQL Server中导入数据二、例题1.查询所有学生的全部信息2.查询学生的学号和姓名3.查询所有学生的姓名和出生年4. 查询所有学生的姓名和出生年&…

【关于Linux中----生产消费模型】

文章目录一、生产消费模型1.1概念的引入1.2 321原则二、条件变量2.1概念的引入2.2理解条件变量2.3条件变量的使用三、基于BlockingQueue的生产者消费者模型3.1BlockingQueue的介绍3.2C queue模拟阻塞队列的生产消费模型3.3对生产消费任务的模拟封装四、遗留问题一、生产消费模型…

基于YOLOv5的水下海洋目标检测

摘要:水下海洋目标检测技术具有广泛的应用前景,可以用于海洋环境监测、海洋资源开发、海洋生物学研究等领域。本文提出了一种基于 YOLOv5 的水下海洋目标检测方法,使用数据增强方法进行了大量实验,并与其他方法进行了对比&#xf…

(SQL学习随笔3)SQL语法——SELECT语句

导航基本认识FROM关键字LIMIT与OFFSETORDER BYWHERE条件查询单值比较多条件组合范围筛选空值匹配LIKE通配条件分组运算符和函数数据变换分组运算表连接内连接左(右)外连接全外连接外键约束窗口函数UNION:表上下拼接子查询条件判断PostgreSQLMySQL基本认识 SELECT t…

【论文阅读】BiSeNet V2用于实时语义分割的双边网络

前言BiSeNet V2延续了v1版本的双边结构,分别处理空间细节信息、高层语义信息。同时设计更简洁高效的结构,进行特征提取,实现高精度和高速度。在训练模型时,使用了增强训练策略 ,添加多个辅助训练分支来促进不同浅层网络…

Spring-aop面向切面

1、理解必要的专业术语 先看看上面图,这是我的个人理解。(画的丑,主打真实) 1)Advice,通知/增强:类方法中提出来的共性功能(大白话就是提出来的重复代码) 2)Pointcut,切入点/切点&#…

【微服务】微服务架构下你不得不知的3种部署策略

文章目录前言滚动部署蓝绿部署金丝雀部署总结前言 不知道大家有了解过你们公司的软件产品是如何部署的么?采用的什么部署策略?其实在软件开发生命周期中,部署是非常关键的一环,你需要考虑多方面的因素,如何保证你部署…

【推荐算法】CTR中embedding层的学习和训练

note 连续特征处理:facebook DLRM模型,对连续值的处理方式是把所有的连续值输入到一个神经网络,然后通过神经网络把它压缩到一个embedding维度大小的一个向量上,然后将Embedding和其他离散特征Embedding Concat起来,再…

springboot-分页功能

1.分页功能的作用 分页功能作为各类网站和系统不可或缺的部分(例如百度搜索结果的分页等) ,当一个页面数据量大的时候分页作用就体现出来的,其作用有以下5个。 (1)减少系统资源的消耗 (2&#…

redis设计与实现读书笔记

这里主要记录一下在阅读redis设计与实现中碰到的一些没有记录过的知识。 引用计数技术 Redis的对象系统实现了基于引用计数技术的内存回收机制,当程序不再使用某个对象的时候,这个对象所占用的内存就会被自动释放;另外,Redis还通过引用计数…

低调且强大--iVX低代码平台

iVX目录前言一、低代码那么多 为什么选择iVX?二、“拼”出来的低代码平台,真的好用吗?三、iVX与其他低代码有啥可比性?前言 首先我们应该明白自动编程突破可能是:领域内Mini LLM 现在的思路都是搞LLM,几乎像…

通俗举例讲解动态链接、静态链接

参考动态链接 - 知乎 加上我自己的理解,比较好懂,但可能在细节方面有偏差,但总体是一致的 静态链接的背景 静态链接使得不同的程序开发者和部门能够相对独立的开发和测试自己的程序模块,从某种意义上来讲大大促进了程序开发的效率&#xf…

NPC 也有了生命?当 ChatGPT 注入游戏你能想象吗

🍎道阻且长,行则将至。🍓 目录引言:西部世界元宇宙,还记得吗ChatGPT 的世界?下图就是一个 ChatGPT 小镇: 引言:西部世界 《西部世界》以一个虚构的游戏般的“西部世界”为背景&am…

springboot验证码生成及验证功能

1.easy-captcha工具包 生成验证码的方式有许多种,这里选择的是easy-captcha工具包。 github开原地址为:easy-captcha工具包 其支持Java图形验证码,支持gif、中文、算术等类型,可用于Java Web、JavaSE等项目。 2添加依赖 首先需…