贯穿设计模式--开闭原则

🌵概述

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

🌾特点

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

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

🌿问题引出

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

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

1. 习题接口:IExercise:

<span style="color:#333333"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#0000ff">package</span> com.ygt.principle.ocp;

<span style="color:#008000">/**
 * 习题接口,主要有价格和姓名
 */</span>
<span style="color:#0000ff">public</span> <span style="color:#0000ff">interface</span> <span style="color:#a31515">IExercise</span> {

    Double <span style="color:#a31515">getPrice</span>();

    String <span style="color:#a31515">getName</span>();
}
</code></span></span>

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

<span style="color:#333333"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#0000ff">package</span> com.ygt.principle.ocp;

<span style="color:#008000">/**
 * 高中习题类
 */</span>
<span style="color:#0000ff">public</span> <span style="color:#0000ff">class</span> <span style="color:#a31515">HighExercise</span> <span style="color:#0000ff">implements</span> <span style="color:#a31515">IExercise</span> {
    <span style="color:#008000">// 习题价格</span>
    <span style="color:#0000ff">private</span> Double price;

    <span style="color:#008000">// 习题名字</span>
    <span style="color:#0000ff">private</span> String name;

    <span style="color:#008000">// 构造方法</span>
    <span style="color:#0000ff">public</span> <span style="color:#a31515">HighExercise</span>(Double price, String name) {
        <span style="color:#0000ff">this</span>.price = price;
        <span style="color:#0000ff">this</span>.name = name;
    }

    <span style="color:#0000ff">public</span> Double <span style="color:#a31515">getPrice</span>() {
        <span style="color:#0000ff">return</span> <span style="color:#0000ff">this</span>.price;
    }

    <span style="color:#0000ff">public</span> String <span style="color:#a31515">getName</span>() {
        <span style="color:#0000ff">return</span> <span style="color:#0000ff">this</span>.name;
    }
}
</code></span></span>

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

<span style="color:#333333"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#0000ff">package</span> com.ygt.principle.ocp;

<span style="color:#0000ff">import</span> java.util.ArrayList;
<span style="color:#0000ff">import</span> java.util.List;

<span style="color:#008000">/**
 * 习题店 专门卖习题集的
 */</span>
<span style="color:#0000ff">public</span> <span style="color:#0000ff">class</span> <span style="color:#a31515">ExerciseStore</span> {


    <span style="color:#008000">// 习题店中包含各种习题集</span>
    <span style="color:#0000ff">private</span> List<IExercise> exerciseList = <span style="color:#0000ff">new</span> <span style="color:#a31515">ArrayList</span><>();

    <span style="color:#008000">// 初始化习题集</span>
    <span style="color:#0000ff">public</span> <span style="color:#a31515">ExerciseStore</span>() {
        exerciseList.add(<span style="color:#0000ff">new</span> <span style="color:#a31515">HighExercise</span>(<span style="color:#880000">63d</span>, <span style="color:#a31515">"五年高考三年模拟数学"</span>));
        exerciseList.add(<span style="color:#0000ff">new</span> <span style="color:#a31515">HighExercise</span>(<span style="color:#880000">53d</span>, <span style="color:#a31515">"五年高考三年模拟语文"</span>));
        exerciseList.add(<span style="color:#0000ff">new</span> <span style="color:#a31515">HighExercise</span>(<span style="color:#880000">43d</span>, <span style="color:#a31515">"五年高考三年模拟英语"</span>));
    }

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

    <span style="color:#008000">// 测试调用习题集</span>
    <span style="color:#0000ff">public</span> <span style="color:#0000ff">static</span> <span style="color:#0000ff">void</span> <span style="color:#a31515">main</span>(String[] args) {
        <span style="color:#a31515">ExerciseStore</span> <span style="color:#008000">store</span> <span style="color:#ab5656">=</span> <span style="color:#0000ff">new</span> <span style="color:#a31515">ExerciseStore</span>();
        store.showExercise();
    }
}
</code></span></span>

4. 演示结果:

<span style="color:#333333"><span style="background-color:#ffffff"><code class="language-java">~~~~~~~~~~~~~~本店拥有的高中习题集~~~~~~~~~~~~~~~
习题名					价格		
五年高考三年模拟数学		¥<span style="color:#880000">63.0</span>元		
五年高考三年模拟语文		¥<span style="color:#880000">53.0</span>元		
五年高考三年模拟英语		¥<span style="color:#880000">43.0</span>元		
</code></span></span>

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

<span style="color:#333333"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#0000ff">package</span> com.ygt.principle.ocp;

<span style="color:#0000ff">public</span> <span style="color:#0000ff">class</span> <span style="color:#a31515">HighExercise</span> <span style="color:#0000ff">implements</span> <span style="color:#a31515">IExercise</span> {
  
    <span style="color:#008000">// ....省略其他代码</span>
   
    <span style="color:#0000ff">public</span> Double <span style="color:#a31515">getPrice</span>() {
        <span style="color:#0000ff">return</span> <span style="color:#0000ff">this</span>.price * <span style="color:#880000">0.85</span>;
    }
}
</code></span></span>

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

☘️解决方案

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

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

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

<span style="color:#333333"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#0000ff">package</span> com.ygt.principle.ocp;

<span style="color:#0000ff">public</span> <span style="color:#0000ff">class</span> <span style="color:#a31515">DiscountHighExercise</span> <span style="color:#0000ff">extends</span> <span style="color:#a31515">HighExercise</span>{

    <span style="color:#0000ff">public</span> <span style="color:#a31515">DiscountHighExercise</span>(Double price, String name) {
        <span style="color:#0000ff">super</span>(price, name);
    }

    <span style="color:#008000">// 重写获取价格方法</span>
    <span style="color:#2b91af">@Override</span>
    <span style="color:#0000ff">public</span> Double <span style="color:#a31515">getPrice</span>() {
        <span style="color:#008000">// 增加价格为原来的85折。</span>
        <span style="color:#0000ff">return</span> <span style="color:#0000ff">super</span>.getPrice() * <span style="color:#880000">0.85</span>;
    }
}
</code></span></span>

再稍微修改下ExerciseStore类即可:

<span style="color:#333333"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#0000ff">package</span> com.ygt.principle.ocp;

<span style="color:#0000ff">import</span> java.util.ArrayList;
<span style="color:#0000ff">import</span> java.util.List;

<span style="color:#008000">/**
 * 习题店 专门卖习题集的
 */</span>
<span style="color:#0000ff">public</span> <span style="color:#0000ff">class</span> <span style="color:#a31515">ExerciseStore</span> {


    <span style="color:#008000">// 习题店中包含各种习题集</span>
    <span style="color:#0000ff">private</span> List<IExercise> exerciseList = <span style="color:#0000ff">new</span> <span style="color:#a31515">ArrayList</span><>();

    <span style="color:#008000">// 初始化习题集</span>
    <span style="color:#0000ff">public</span> <span style="color:#a31515">ExerciseStore</span>() {
        <span style="color:#008000">// 修改地方,将创建类改成DiscountHighExercise</span>
        exerciseList.add(<span style="color:#0000ff">new</span> <span style="color:#a31515">DiscountHighExercise</span>(<span style="color:#880000">63d</span>, <span style="color:#a31515">"五年高考三年模拟数学"</span>));
        exerciseList.add(<span style="color:#0000ff">new</span> <span style="color:#a31515">DiscountHighExercise</span>(<span style="color:#880000">53d</span>, <span style="color:#a31515">"五年高考三年模拟语文"</span>));
        exerciseList.add(<span style="color:#0000ff">new</span> <span style="color:#a31515">DiscountHighExercise</span>(<span style="color:#880000">43d</span>, <span style="color:#a31515">"五年高考三年模拟英语"</span>));
    }

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

    <span style="color:#008000">// 测试调用习题集</span>
    <span style="color:#0000ff">public</span> <span style="color:#0000ff">static</span> <span style="color:#0000ff">void</span> <span style="color:#a31515">main</span>(String[] args) {
        <span style="color:#a31515">ExerciseStore</span> <span style="color:#008000">store</span> <span style="color:#ab5656">=</span> <span style="color:#0000ff">new</span> <span style="color:#a31515">ExerciseStore</span>();
        store.showExercise();
    }
}
</code></span></span>

再看下执行结果:

<span style="color:#333333"><span style="background-color:#ffffff"><code class="language-java">~~~~~~~~~~~~~~本店拥有的高中习题集~~~~~~~~~~~~~~~
习题名					价格		
五年高考三年模拟数学		¥<span style="color:#880000">53.55</span>元		
五年高考三年模拟语文		¥<span style="color:#880000">45.05</span>元		
五年高考三年模拟英语		¥<span style="color:#880000">36.55</span>元	
</code></span></span>

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

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

🌸 完结

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

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

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

 

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

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

相关文章

Windows驱动开发必备工具

Windows驱动开发必备工具 设备树文软件 可以查看设备信息 数字签名工具安装包 开发用的数字签名证书密钥 断点命中工具包&#xff08;双机调试必备&#xff09; 二进制文件解析工具 日志查看工具&#xff08;必备&#xff09; IRP查看工具 C驱动开发相关书籍 有需要工具、书籍…

怎么学习CSS相关技术知识? - 易智编译EaseEditing

学习CSS技术是前端开发中的重要一环&#xff0c;它用于控制网页的样式和布局&#xff0c;使网页更加美观和易于使用。以下是学习CSS技术的几个方面&#xff1a; 基本语法和选择器&#xff1a; 了解CSS的基本语法&#xff0c;学习如何使用选择器来选择HTML元素并应用样式。 样…

vim、awk、tail、grep的使用

vim命令 $定位到光标所在行的行末^定位到光标所在行的行首gg定位到文件的首行G定位到文件的末行dd删除光标所在行ndd删除n行&#xff08;从光标所在行开始&#xff09;D删除光标所在行&#xff0c;使之变为空白行x删除光标所在位置字符nx删除n个字符&#xff0c;从光标开始向后…

使用Flutter的image_picker插件实现设备的相册的访问和拍照

文章目录 需求描述Flutter插件image_picker的介绍使用步骤1、添加依赖2、导入 例子完整的代码效果 总结 需求描述 在应用开发时&#xff0c;我们有很多场景要使用到更换图片的功能&#xff0c;即将原本的图像替换设置成其他的图像&#xff0c;从设备的相册或相机中选择图片或拍…

CAD .NET 15.0 企业版 Crack

CAD .NET 15.0 企业版 企业版 企业版 企业版 企业版 Updated: June 14, 2023 | Version 15.0 NEW CAD .NET is a library for developing solutions in .NET environment. It supports AutoCAD DWG/ DXF, PLT and other CAD formats. The library can be used in a wide rang…

visual studio 生成dll文件以及修改输出dll文件名称操作

目录 visual studio 生成dll文件以及修改dll文件名称一、准备测试代码二、设置导出dll属性三、生成dll文件 .lib .dll .pdb 的简单介绍dll文件使用方式lib文件使用方式1、动态链接 &#xff08;原理&#xff09;2、静态链接&#xff1a; visual studio 生成dll文件以及修改dll文…

flex 弹性布局

Flex 布局的使用 任何一个容器都可以指定为 Flex 布局。 .box{ display: flex; //flex作为display的一个属性使用 } 行内元素也可以使用 Flex 布局。 .box{ display: inline-flex; } 注意&#xff1a;设为 Flex 布局以后&#xff0c;子元素的float、clear和vertical-align…

MySQL做分布式锁

分布式锁mysql实现方式 方式1&#xff1a;唯一索引 创建锁表&#xff0c;内部存在字段表示资源名及资源描述&#xff0c;同一资源名使用数据库唯一性限制。多个进程同时往数据库锁表中写入对某个资源的占有记录&#xff0c;当某个进程成功写入时则表示其获取锁成功其他进程由于…

备战秋招 | 笔试强化22

目录 一、选择题 二、编程题 三、选择题题解 四、编程题题解 一、选择题 1、在有序双向链表中定位删除一个元素的平均时间复杂度为 A. O(1) B. O(N) C. O(logN) D. O(N*logN) 2、在一个以 h 为头指针的单循环链表中&#xff0c;p 指针指向链尾结点的条件是( ) A. p->ne…

小程序云开发快速入门(2/4)

前言 我们对《微信小程序云开发快速入门&#xff08;1/4&#xff09;》的知识进行回顾一下。在上章节我们知道了云开发的优势以及能力&#xff0c;并且我们还完成了码仔备忘录的本地版到网络版的改造&#xff0c;主要学习了云数据库同时还通过在小程序使用云API直接操作了云数…

【无标题】uniapp引入萤石云 真机无法运行 踩坑集合

Uniapp 接入萤石云 踩坑 1.先用了 UIKit Javascript 就是在 pc端 那套流程 npm install ezuikit-jsimport EZUIKit from ezuikit-js;这套流程貌似只适用于pc端&#xff0c;我在接入uniapp的时候没看官网 以为都是一套流程&#xff0c;然后就在uniapp中也来了这一套&#xff0…

Linux安装部署并使用Redis(包含Redis Desktop Manager界面化工具)

文章目录 前言一、Redis的简介二、redis的安装与配置&#xff08;Linux环境&#xff09;三、redis的使用&#xff08;Redis Desktop Manager界面化&#xff09;四、基本命令**String基本命令&#xff1a;****hash基本命令&#xff1a;****List基本命令&#xff1a;****set基本命…

Python高阶技巧 网络编程

Socket ocket (简称 套接字) 是进程之间通信一个工具&#xff0c;好比现实生活中的插座&#xff0c;所有的家用电器要想工作都是基于插座进行&#xff0c;进程之间想要进行网络通信需要socket。 Socket负责进程之间的网络数据传输&#xff0c;好比数据的搬运工。 客户端和服务…

364 · 接雨水 II

链接&#xff1a;九章算法 - 帮助更多程序员找到好工作&#xff0c;硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧 题解&#xff1a; 九章算法 - 帮助更多程序员找到好工作&#xff0c;硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧

数据库访问中间件--springdata-jpa的基本使用

二、单表SQL操作-使用关键字拼凑方法 回顾 public interface UserRepository extends JpaRepository<User,Integer> {User findByUsernameLike(String username); }GetMapping("/user/username/{username}")public Object findUserByUsername(PathVariable S…

[回馈]ASP.NET Core MVC开发实战之商城系统(四)

经过一段时间的准备&#xff0c;新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始&#xff0c;在之前的文章中&#xff0c;讲解了商城系统的整体功能设计&#xff0c;页面布局设计&#xff0c;环境搭建&#xff0c;系统配置&#xff0c;及首页【商品类型&#xff0c;ba…

C# Blazor 学习笔记(6):热重置问题解决

文章目录 前言热重置问题描述解决方法演示 总结 前言 我最近在使用Blazor的时候&#xff0c;使用了BootstrapBlazor&#xff08;以下简称BB&#xff09;创建模板的时候&#xff0c;发现热重置无效。经过了一上午的折腾&#xff0c;我终于解决了这个问题。 热重置 问题描述 …

Day12-1-Webpack前端工程化开发

Webpack前端工程化 1 案例-webpack打包js文件 1 在index.html中编写代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><me…

机器学习04-数据理解之数据可视化-(基于Pima数据集)

什么是数据可视化? 数据可视化是指通过图表、图形、地图等视觉元素将数据呈现出来的过程。它是将抽象的、复杂的数据转化为直观、易于理解的视觉表达的一种方法。数据可视化的目的是帮助人们更好地理解数据&#xff0c;从中发现模式、趋势、关联和异常&#xff0c;从而作出更明…

COMSOL三维多孔介质3D多相材料颗粒夹杂复合材料达西渗流模拟

在实际工程中渗流路径往往不是单一材料&#xff0c;如渗流发生在夹杂碎石的土体中&#xff0c;这就造成渗流的复杂性。这里采用两项材料通过COMSOL达西定律模块对渗流进行模拟。 模型采用CAD随机球体颗粒&过渡区插件建立后导入到COMSOL软件内。 模型包括渗流发生的外侧基…