贯穿设计模式第二话--开闭职责原则

news2024/12/29 8:41:55

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

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

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

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

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

📃前言回顾


​ 🔥【贯穿设计模式】第一话·设计模式初介绍和单一职责原则🔥

在第一篇文章中,我们了解设计模式有七大原则,是我们在学习设计模式的基础,我们也学习到了第一个原则:单一职责原则;

我们来回顾下,它的定义:指对一个类来说,应当只有一个引起它变化的原因,否则类应该被拆分,即一个类应该只有一个职责。

并且我们通过学生上课的例子讲解并认识到各个阶段的代码所遇到的问题,也有优缺点,所以在应用单一职责原则时,只有逻辑足够简单,才可以在代码级别上违反单一职责原则;只有类中方法数量足够少,才可以在方法级别上违反单一职责原则。

🌴开闭原则

今天我们要学习的是开闭原则,对扩展开放,对修改关闭。

🌵概述

  • 该原则主要说明的是扩展开放,对修改关闭,即尽量通过扩展软件实体类等来解决需求变化,而不是通过修改已有的代码来完成变化;
  • 实现开闭原则的核心思想就是面向抽象编程,强调的是用抽象构建框架,用实现扩展细节,可以提高软件系统的可复用性及可维护性;
  • 简单理解就是说将功能模块以接口的方式来调用,对功能进行抽象化,并且外部能够实现该功能(接口)。
  • 在一个软件产品在生命周期内,都会发生变化、升级和维护等一系列原因,可能需要对软件原有代码进行修改,也会有可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。既然变化是一个既定的事实,我们就应该在设计的时候尽量适应这些变化,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有代码来实现变化,以此提高项目的稳定性和灵活性;
  • 而举一个生活例子,在现在的互联网公司中,都比较流行一个弹性化工作制,规定每天工作8小时。这个每天工作8小时这个规定是关闭的,但是什么时候来、什么时候走是开放的,早来早走,晚来晚走。因为晚上加班都是时常发生的事情,你有可能凌晨1点才上班,如果第二天要求你9点就得来上班,我相信你估计是起不来的,甚至到公司都会打瞌睡的状态。

🌾特点

开闭原则是编程中最基础最重要的设计原则,如果遵循开闭原则将有以下优点

  • 提高系统的复用性。代码粒度越小,被复用的可能性就越大。开闭原则的设计保证系统是实现了复用的系统。
  • 提高系统的可维护性。一个产品上线后,维护人员的工作不仅仅是对数据进行维护,还可能对程序进行扩展。开闭原则对已有软件模块的要求不能再修改,去扩展一个新类,这就使变化中的软件系统有一定的稳定性和延续性,便于系统的维护。
  • 提高系统的灵活性。我们要知道,需求是无时无刻在变化的,在软件系统面临新的需求时,系统的设计必须是稳定的。开闭原则可以通过扩展已有的软件系统,提供新的行为,能快速应对变化,以满足对软件新的需求,使变化中的软件系统有一定的适应性和灵活性。

🌿问题引出

遥想当初上学时期,甚至在高中的时候,每天的时间都会被大量的习题集,试卷,课后作业占据,除了刷题,就是刷题了,似乎只要刷多了,你就会了。哈哈这里就不细讲当初刷题的苦逼日子了。接下来就以这些习题集等例子来讲解开闭原则吧。

整个习题集的类图如图所示:

1. 习题接口:IExercise:

package com.ygt.principle.ocp;

/**
 * 习题接口,主要有价格和姓名
 */
public interface IExercise {

    Double getPrice();

    String getName();
}

2. 高中习题类实现了习题接口:HighExercise:

package com.ygt.principle.ocp;

/**
 * 高中习题类
 */
public class HighExercise implements IExercise {
    // 习题价格
    private Double price;

    // 习题名字
    private String name;

    // 构造方法
    public HighExercise(Double price, String name) {
        this.price = price;
        this.name = name;
    }

    public Double getPrice() {
        return this.price;
    }

    public String getName() {
        return this.name;
    }
}

3. 习题集店贩卖习题:ExerciseStore:

package com.ygt.principle.ocp;

import java.util.ArrayList;
import java.util.List;

/**
 * 习题店 专门卖习题集的
 */
public class ExerciseStore {


    // 习题店中包含各种习题集
    private List<IExercise> exerciseList = new ArrayList<>();

    // 初始化习题集
    public ExerciseStore() {
        exerciseList.add(new HighExercise(63d, "五年高考三年模拟数学"));
        exerciseList.add(new HighExercise(53d, "五年高考三年模拟语文"));
        exerciseList.add(new HighExercise(43d, "五年高考三年模拟英语"));
    }

    // 展示习题集方法
    public void showExercise() {
        System.out.println("~~~~~~~~~~~~~~本店拥有的高中习题集~~~~~~~~~~~~~~~");
        System.out.println("习题名\t\t\t\t\t价格\t\t");
        exerciseList.forEach(e-> System.out.println(e.getName() + "\t\t¥" + e.getPrice() + "元\t\t"));
    }

    // 测试调用习题集
    public static void main(String[] args) {
        ExerciseStore store = new ExerciseStore();
        store.showExercise();
    }
}

4. 演示结果:

~~~~~~~~~~~~~~本店拥有的高中习题集~~~~~~~~~~~~~~~
习题名					价格		
五年高考三年模拟数学		¥63.0元		
五年高考三年模拟语文		¥53.0元		
五年高考三年模拟英语		¥43.0

按照上面的写法,我们可以轻松写出习题店售卖习题集的过程,但是习题店每逢寒暑假的时候,为了让广大学子都能做上习题,习题店决定按照8.5折的强大优惠力度促进销售习题,而这时候就需要对现有的售卖习题的过程进行修改。如果按照原先的思路的话,就会直接在HighExercise类上,直接将价格修改。

package com.ygt.principle.ocp;

public class HighExercise implements IExercise {
  
    // ....省略其他代码
   
    public Double getPrice() {
        return this.price * 0.85;
    }
}

下面就一起来探讨下解决方法吧。

☘️解决方案

如果直接修改原先的习题类的话,就会导致不是遵循了开闭原则了,违反了对修改关闭的原则,所以此时不能直接修改HighExercise类或者是IExercise接口了。而是通过扩展一个类来完成该修改价格的需求。

增加一个子类DiscountHighExercise继承HighExercise类来完成:

注意上面修改的HighExercise类中的getPrice()方法应该恢复原先。

package com.ygt.principle.ocp;

public class DiscountHighExercise extends HighExercise{

    public DiscountHighExercise(Double price, String name) {
        super(price, name);
    }

    // 重写获取价格方法
    @Override
    public Double getPrice() {
        // 增加价格为原来的85折。
        return super.getPrice() * 0.85;
    }
}

再稍微修改下ExerciseStore类即可:

package com.ygt.principle.ocp;

import java.util.ArrayList;
import java.util.List;

/**
 * 习题店 专门卖习题集的
 */
public class ExerciseStore {


    // 习题店中包含各种习题集
    private List<IExercise> exerciseList = new ArrayList<>();

    // 初始化习题集
    public ExerciseStore() {
        // 修改地方,将创建类改成DiscountHighExercise
        exerciseList.add(new DiscountHighExercise(63d, "五年高考三年模拟数学"));
        exerciseList.add(new DiscountHighExercise(53d, "五年高考三年模拟语文"));
        exerciseList.add(new DiscountHighExercise(43d, "五年高考三年模拟英语"));
    }

    // 展示习题集方法
    public void showExercise() {
        System.out.println("~~~~~~~~~~~~~~本店拥有的高中习题集~~~~~~~~~~~~~~~");
        System.out.println("习题名\t\t\t\t\t价格\t\t");
        exerciseList.forEach(e-> System.out.println(e.getName() + "\t\t¥" + e.getPrice() + "元\t\t"));
    }

    // 测试调用习题集
    public static void main(String[] args) {
        ExerciseStore store = new ExerciseStore();
        store.showExercise();
    }
}

再看下执行结果:

~~~~~~~~~~~~~~本店拥有的高中习题集~~~~~~~~~~~~~~~
习题名					价格		
五年高考三年模拟数学		¥53.55元		
五年高考三年模拟语文		¥45.05元		
五年高考三年模拟英语		¥36.55

这样通过增加一个DiscountHighExercise类,修改ExerciseStore中少量的代码,就可以实现习题集价格的85折的需求啦,而其他部分没有任何变动,体现了开闭原则的应用。

注意的一点:开闭原则是对扩展开放,对修改关闭,但这并不意味着不做任何修改,低层模块的变更,必然要有高层模块进行耦合,否则就是一个孤立无意义的代码片段。

🌸 完结

相信各位看官看到这里大致都对设计模式中的其中一个原则有了了解吧,开闭原则实际上的定义就是扩展开放,对修改关闭,提高软件系统的可复用性及可维护性。

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

文章的最后来个小小的思维导图:
在这里插入图片描述

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

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

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

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

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

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

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

相关文章

串口数据处理

1.在串口接收中断中接收到的数据写入环形缓冲区&#xff1b;唤醒解析线程(发出任务通知)或释放信号量。 2.开一个解析线程&#xff1a; void AT_Parser() {while(1){1.等待任务通知&#xff1b;读环形缓冲区&#xff08;将数据存起来&#xff09;&#xff1b; 2.常…

FE_CSS 页面布局之浮动

网页布局的本质——用 CSS 来摆放盒子。 把盒子摆放到相应位置。CSS 提供了三种传统布局方式(简单说,就是盒子如何进行排列顺序)&#xff1a; 普通流&#xff08;标准流&#xff09;浮动定位 1 标准流&#xff08;普通流/文档流&#xff09; 所谓的标准流: 就是标签按照规定…

LAMP架构与网站搭建实例

一.LAMP概述 1、LAMP的概念 LAMP架构是目前成熟的企业网站应用模式之一&#xff0c;指的是协同工作的一整套系统和相关软件&#xff0c;能够提供动态web站点服务及其应用开发环境 LAMP是一个缩写词&#xff0c;具体包括Linux操作系统、Apache网站服务器、MySQL数据库服务器、…

53 openEuler搭建PostgreSQL数据库服务器-管理数据库

文章目录53 openEuler搭建PostgreSQL数据库服务器-管理数据库53.1 创建数据库创建数据库示例53.2 选择数据库选择数据库示例53.3 查看数据库查看数据库示例53.4 删除数据库删除数据库示例53.5 备份数据库备份数据库示例53.6 恢复数据库恢复数据库示例53 openEuler搭建PostgreSQ…

第十四届蓝桥杯省赛c/c++大学B组题解

第十四届蓝桥杯省赛c/c大学B组题解 个人答案&#xff0c;有错漏感谢指正哈 试题 A: 日期统计 本题总分&#xff1a;5 分 【问题描述】   小蓝现在有一个长度为 100 的数组&#xff0c;数组中的每个元素的值都在 0 到 9 的范围之内。数组中的元素从左至右如下所示&#xff…

Linux应用编程(文件属性与目录)

本章将会讨论如下主题内容。 ⚫ Linux 系统的文件类型&#xff1b; ⚫ stat 系统调用&#xff1b; ⚫ 文件各种属性介绍&#xff1a;文件属主、访问权限、时间戳&#xff1b; ⚫ 符号链接与硬链接&#xff1b; ⚫ 目录&#xff1b; ⚫ 删除文件与文件重命名。 一、Linux 系统中…

python编写一计票程序,键盘输入候选人姓名(输入“#”结束),使用字典存储并统计出候选人得票数。python实现分段函数。

一、编程题目 编程题目1&#xff1a;python编写一计票程序&#xff0c;键盘输入候选人姓名(输入“#”结束)&#xff0c;使用字典存储并统计出候选人得票数。 编程题目2&#xff1a;python实现以下分段函数&#xff1a; y 2x^34x^23 -10<x<0 y x14 0<x<6 y 6x…

001+limou+git安装与入门

1、git安装以及下载检查&#xff08;windows环境&#xff0c;macOS可能比较麻烦&#xff09; &#xff08;1&#xff09;下载git git官网下载&#xff0c; Git - Downloading Package (git-scm.com) &#xff08;2&#xff09;检查下载 以下命令可以检查git是否下载成功 $…

JAVA入坑之类和对象

目录 一、类 1.1面向对象(OOP)与面向过程 1.2面向对象的三个特性 1.3类的语法格式 1.3.1类的分类 1.3.2类修饰符 1.4变量 1.4.1变量格式 1.4.2成员变量 1.4.3区分实例变量和类变量 1.4.4局部变量 1.4.5区分成员变量和局部变量 1.5final关键字 1.5.1常量 1.6方法 …

基于Java+SSM+jsp的二手车交易网站设计与实现【源码(完整源码请私聊)+论文+演示视频+包运行成功】

博主介绍&#xff1a;专注于Java技术领域和毕业项目实战 &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案例&#xff08;300套&#xff09; 目录 一、效果演示 二、…

博客首页效果

学习来自风宇blog的博客首页效果 全部用的基本上都是原生的html&#xff0c;css&#xff0c;js特别是flex布局的使用&#xff0c;主轴方向可以是横轴&#xff0c;也可以是纵轴&#xff0c;弹性项还可可以使用百分比sticky粘性布局&#xff0c;作为侧边栏&#xff0c;它不会超出…

Spring Cloud组件源码之OpenFeign源码分析

" Spring 到底是春天的来临万物复苏&#xff0c;还是春转夏的干燥又炎热呢&#xff1f;" Spring的来临让JavaEE走向了另一个高度。便捷的开发&#xff0c;完美的生态。物极必反&#xff0c;学习Spring的成本越来越低&#xff0c;导致Java程序员越来越密集&#xff0…

实习不对口,还去吗?

作者&#xff1a;阿秀校招八股文学习网站&#xff1a;https://interviewguide.cn这是阿秀的第「255」篇原创小伙伴们大家好&#xff0c;我是阿秀。欢迎今年参加秋招的小伙伴加入我的学习圈&#xff0c;目前已经超过 2200 小伙伴加入&#xff01;去年认真准备和走下来的基本都拿…

LBS计算附近的对象:MySQL 空间索引方式

目录1. MySQL空间数据类型的基本介绍1.1 什么是MySQL空间数据类型1.2 有哪些空间数据类型1.3 支持空间数据类型的引擎1.4 坐标系类型2. 存储坐标系的示例代码2.1 geomtry和point都可以存储坐标系&#xff0c;有什么区别呢&#xff1f;2.2 创建测试表2.3 新增坐标2.3 计算两地之…

计组2.1——计算机中的数据

问题&#xff1a;数据如何在计算机中表示&#xff1f; 运算器如何进行数字运算和逻辑运算&#xff1f; 计组2.11.进制转化&#xff1a;2. BCD码3.字符和字符串1.ASCII2.汉字编码3.字符串4.奇偶校验码1. 校验原理3. 奇偶校验5.汉明码6.循环冗余校验码1.进制转化&#xff1a; #me…

【C语言】关于文件操作你知多少?

目录 一.引入 二. 什么是文件 2.1 什么是文件 2.2 程序文件 2.3 数据文件 2.4 文件名 三.文件的打开和关闭 3.1 文件指针 3.2 文件的打开和关闭 四.文件的顺序读写 4.1 函数汇总 4.2 printf/fprintf/sprintf 4.3 scanf/fscanf/sscanf 五. 文件的随机读写 5.1 引入 5.2 fsee…

HTML5 <ins> 标签、HTML5 <link> 标签

HTML5 <ins> 标签 实例 一段带有已删除部分和新插入部分的文本&#xff1a; <p>My favorite color is <del>blue</del> <ins>red</ins>!</p> 尝试一下 浏览器支持 所有主流浏览器都支持 <ins> 标签。 标签定义及使用说明 …

Sentry安装使用(最全最细)

Sentry安装使用(最全最细&#xff0c;包括解决邮箱发送问题&#xff0c;https上传问题&#xff0c;https访问问题&#xff0c;安装此教程配置即可) ##服务器操作系统为2核8G,CentOS7.9 ##安装Docker-ce yum install -y yum-utils \device-mapper-persistent-data \lvm2yum-c…

日撸 Java 三百行day27

文章目录说明day27 Hanoi 塔问题1.思路2.代码3.图示说明 闵老师的文章链接&#xff1a; 日撸 Java 三百行&#xff08;总述&#xff09;_minfanphd的博客-CSDN博客 自己也把手敲的代码放在了github上维护&#xff1a;https://github.com/fulisha-ok/sampledata day27 Hanoi 塔…

部署LAMP架构和论坛

引言 LAMP架构是目前成熟的企业网站应用模式之一&#xff0c;指的是协同工作的一整套系统和相关软件&#xff0c;能够提供动态Web站点服务及其应用开发环境。LAMP是一个缩写词&#xff0c;具体包括Linux操作系统、Apache网站服务器、MySQL数据库服务器、PHP&#xff08;或Perl、…