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

软件设计原则-开闭原则讲解以及代码示例

开闭原则

一,介绍

1.前言

开闭原则(Open-Closed Principle,OCP)是面向对象设计中的一条重要原则,它由Bertrand Meyer在其著作《面向对象软件构造》中提出,并成为SOLID原则之一。

开闭原则的核心思想是:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。简单来说,就是在不修改已有代码的情况下,通过扩展来实现新的功能或变化。

2.何时使用开闭原则

  1. 当需要添加新功能时:如果你需要在已有的代码基础上添加新功能,你应该通过扩展现有代码,而不是直接修改已有代码。这样做的好处是不会对原有的功能产生影响,同时也保证了代码的可维护性和稳定性。

  2. 当需要修改已有功能时:尽管开闭原则主张对已有代码进行关闭,但有时我们仍然需要修改一些已有功能。这种情况下,可以考虑通过使用抽象层、接口或者设计模式来隔离修改的影响范围,从而保持已有功能的稳定性,而不必修改大量的代码。

  3. 当需要适应变化:在软件开发过程中,需求和业务环境可能会发生变化。为了应对这种变化,我们需要让系统具备良好的扩展性。通过遵循开闭原则,我们可以更容易地添加、调整或替换组件,以适应变化的需求。

二,代码示例

为了更详细地介绍开闭原则,我们可以通过一个例子来说明:

假设有一个图形绘制程序,程序需要能够绘制不同形状的图形,比如矩形、圆形和三角形。最初的设计可能会像这样:
 

class Shape {private String type;public Shape(String type) {this.type = type;}public void draw() {if (type.equals("rectangle")) {System.out.println("绘制矩形");} else if (type.equals("circle")) {System.out.println("绘制圆形");} else if (type.equals("triangle")) {System.out.println("绘制三角形");}}
}

这个设计看起来似乎没有问题,但问题在于当我们需要添加新的图形类型时,需要修改`Shape`类的源代码,违背了开闭原则。

为了符合开闭原则,我们可以进行重构。首先,我们定义一个抽象类`Shape`:


 

abstract class Shape {public abstract void draw();
}

然后,对每种具体的图形类型,创建一个子类并实现`draw()`方法:
 

class Rectangle extends Shape {@Overridepublic void draw() {System.out.println("绘制矩形");}
}class Circle extends Shape {@Overridepublic void draw() {System.out.println("绘制圆形");}
}class Triangle extends Shape {@Overridepublic void draw() {System.out.println("绘制三角形");}
}

现在,我们可以通过扩展子类来添加新的图形类型,而无需修改`Shape`类的源代码。例如,如果需要添加椭圆形,只需创建一个`Ellipse`类,并实现`draw()`方法即可。

这个重构后的设计符合开闭原则,因为我们通过扩展子类来实现新的功能,而不需要修改父类的代码。这样做的好处是,已有的代码保持不变,不会引入新的错误,同时也增加了系统的可扩展性和可维护性。

总结起来,开闭原则鼓励我们在设计软件时,采用抽象、封装和多态等方式,使得系统能够以最小的修改来适应变化。这种设计思想能够提高代码的可复用性、可扩展性和可维护性,是良好的软件设计实践之一。

三,优缺点

开闭原则的优点:

1. 提高了代码的可维护性与复用性:遵循开闭原则可以让代码更加稳定和可维护,同时也使得代码更容易被复用。如果我们需要修改某个模块的行为,只需要扩展该模块而不需要直接修改源代码,这样就不会影响到其他的模块。

2. 提高了代码的可扩展性:开闭原则还可以提高代码的可扩展性。通过扩展已有的代码,我们可以很容易地添加新的功能或改进现有功能,从而适应业务需求的更改。

3. 提高了代码的可测试性:遵循开闭原则可以降低代码的耦合度,使得测试更加容易。因为我们只需要测试新增的代码,而不必验证已有代码的正确性。

开闭原则的缺点:

1. 对代码的设计要求高:遵循开闭原则需要对代码进行良好的抽象和封装,这对程序员的设计能力和经验要求较高。如果设计不好,可能会导致代码过于复杂难以维护。

2. 可能会增加代码量:通过扩展已有的代码来实现新功能,可能会增加代码量,使得系统变得更加复杂。这需要我们在平衡可维护性和代码量之间做出权衡。

3. 可能会带来设计上的限制:在某些情况下,为了遵循开闭原则,我们可能需要引入更多的抽象层或接口。这可能会带来一定的设计上的限制,限制了代码的表达能力和灵活性。

总之,开闭原则是一条非常重要的设计原则,可以提高代码的可维护性、可复用性和可扩展性,但也需要平衡代码的表达能力和灵活性,避免过度设计。

四,Java那里用到了开闭原则

在Java中,开闭原则(Open-Closed Principle)是面向对象设计原则之一,它强调软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。在Java的各个层面都可以应用开闭原则,下面是几个常见的应用场景:

1. 接口和抽象类:通过定义接口和抽象类,可以为系统定义一组稳定的抽象层,对扩展开放。其他具体的实现类可以继承或实现这些抽象层,通过扩展的方式增加新的功能,而无需修改已有的代码。

2. 使用多态性:Java的多态性机制支持开闭原则的实现。通过基类或接口引用指向子类对象,程序可以在不修改原有代码的情况下,动态地添加新的子类,扩展系统的功能。

3. 设计模式:许多设计模式都是基于开闭原则的思想,通过封装变化和抽象稳定部分,实现对扩展开放,对修改关闭。例如,策略模式、观察者模式、装饰器模式等都可以帮助实现开闭原则。

4. 使用反射机制:Java的反射机制可以动态地获取和操作类、方法、属性等信息,提供了一种在运行时操作类结构的能力。通过反射,可以在不修改代码的情况下,动态地实例化对象、调用方法等,实现对系统的扩展。

5. 使用依赖注入(Dependency Injection):依赖注入是一种实现开闭原则的常见方式。通过将依赖关系的创建和管理交由框架来完成,可以在不修改源代码的情况下,通过配置文件或注解改变依赖的实现,从而扩展系统的功能。

总的来说,Java作为一门面向对象的编程语言,提供了许多机制和设计模式来支持开闭原则的实现。合理运用接口和抽象类、多态性、设计模式、反射机制以及依赖注入等技术手段,可以使Java程序更具可扩展性和可维护性,符合开闭原则的设计原则。

五,总结

1.常规总结

本文介绍了开闭原则(Open-Closed Principle,OCP)的基本概念和作用,即软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。通过一个图形绘制程序的例子,说明如何遵循开闭原则使得代码更加稳定、可维护、可扩展和可测试。同时,本文也分析了开闭原则的优缺点,需要平衡代码的可维护性、可复用性和可扩展性,避免过度设计。

2.幽默总结

开闭原则就是让你的代码像女朋友一样,对改进开放,对修改关闭。要保持稳定,可扩展和可维护,但是也要注意不要设计过度,否则就像约会时穿太多衣服一样僵硬。

3.搞笑总结

开闭原则是指软件实体应该对扩展开放,对修改关闭。这意味着我们应该通过扩展来实现新的功能,而不是直接修改已有代码。这样做的好处是可以提高代码的可维护性、复用性和可扩展性。虽然遵循开闭原则需要对代码进行良好的抽象和封装,而且可能会增加代码量和带来设计上的限制,但是这条原则仍然是非常重要的。如果你违反了开闭原则,那么你就是在自找麻烦!

相关文章:

软件设计原则-开闭原则讲解以及代码示例

开闭原则 一,介绍 1.前言 开闭原则(Open-Closed Principle,OCP)是面向对象设计中的一条重要原则,它由Bertrand Meyer在其著作《面向对象软件构造》中提出,并成为SOLID原则之一。 开闭原则的核心思想是&…...

分类预测 | MATLAB实现SSA-CNN-GRU-Attention数据分类预测(SE注意力机制)

分类预测 | MATLAB实现SSA-CNN-GRU-Attention数据分类预测(SE注意力机制) 目录 分类预测 | MATLAB实现SSA-CNN-GRU-Attention数据分类预测(SE注意力机制)分类效果基本描述模型描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现…...

LeetCode--180 连续出现的数字

文章目录 1 题目描述2 结果示例3 解题思路3.1 MySQL 代码 4 知识拓展 1 题目描述 Logs表: ---------------------- | Column Name | Type | ---------------------- | id | int | | num | varchar | ----------------------在 SQL 中,id …...

面试算法34:外星语言是否排序

题目 有一门外星语言,它的字母表刚好包含所有的英文小写字母,只是字母表的顺序不同。给定一组单词和字母表顺序,请判断这些单词是否按照字母表的顺序排序。例如,输入一组单词[“offer”,“is”,“coming”…...

常用docker命令 docker_cmd_sheet

查看所有docker 容器 docker ps 查看 特定docker容器 比如con1 docker ps | grep con1 查看镜像 docker images 拉取镜像 docker pull imageXXX 打标签 docker tag imageXXX:1.4.0 镜像名冒号tag 按照docker-compose.yml 启动容器,在有docker-compose…...

算法进阶——数组中的逆序对

题目 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007 数据范围:对于 50% 的数据, size≤104 对…...

hackmyvm之gift

hackmyvm是一个平台,包含了大量靶机,类似于vulnhub、hackthebox等平台,你可以在上面下载靶机,进行渗透测试练习,非常适合热爱黑客技术或从事渗透测试的人员。 (这段解释参考这篇文章) 下载安装…...

1024,向着“顶尖程序员“迈进

10月24日,对每个程序员而言,都是一个具有特殊意义的日子。1024这个数字,不再只是计算机存储容量的基础单位,更是我们向着技术巅峰进发的象征。 回顾我的程序员之路,那是一个不断学习、不断成长的过程。起初是对编程充…...

Arcgis 数据操作

在进行数据操作的时候,需要注意坐标系要一致,这是前提。 数据类型 文件地理数据库:gbd 个人地理数据库:mdb (Mircosoft Access) 矢量数据:shp 推荐使用gbd数据,效率会更高。 采…...

YoloV7改进策略:SwiftFormer,全网首发,独家改进的高效加性注意力用于实时移动视觉应用的模型,重构YoloV7

文章目录 摘要论文:《SwiftFormer:基于Transformer的高效加性注意力用于实时移动视觉应用的模型》1、简介2、相关研究3、方法3.1、注意力模块概述3.2、高效的加性注意力3.3、SwiftFormer 架构4、实验4.1、实现细节4.2、基线比较4.3、图像分类4.4、目标检测和实例分割4.5、语义…...

Day07 Stream流递归Map集合Collections可变参数

Stream 也叫Stream流,是Jdk8开始新增的一套API (java.util.stream.*),可以用于操作集合或者数组的数据。 Stream流大量的结合了Lambda的语法风格来编程,提供了一种更加强大,更加简单的方式操作 public class Demo1 {public stati…...

8.JavaScript-注释

题记 javascript注释 单行注释 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>实例</title> </head> <body><h1 id"myH1"></h1> <p id"myP"></p>…...

知识分享|分段函数线性化及matlab测试

目录 1 使用0-1变量将分段函数转换为线性约束 2 连续函数采用分段线性化示例 3 matlab程序测试 4 matlab测试结果说明 5 分段线性化应用 1 使用0-1变量将分段函数转换为线性约束 2 连续函数采用分段线性化示例 3 matlab程序测试 clc;clear all; gn10;tn1; x_pfsdpvar(1, t…...

ant target的depends属性

ant的target使用depends属性指明对其它target的依赖。可以依赖多个target&#xff0c;被依赖的多个target之间用逗号分隔。 ant会确保被依赖的target首先执行&#xff0c;然后再执行本target。 ant尽量按照depends属性中指明的target出现的顺序来执行&#xff08;从左到右&…...

【三维重建】DreamGaussian:高斯splatting的单视图3D内容生成(原理+代码)

文章目录 摘要一、前言二、相关工作2.1 3D表示2.2 Text-to-3D2.3 Image-to-3D 三、本文方法3.1生成式 高斯 splitting3.2 高效的 mesh 提取3.3 UV空间的纹理优化 四. 实验4.1实施细节4.2 定性比较4.3 定量比较4.4 消融实验 总结&#xff08;特点、局限性&#xff09; 五、安装与…...

如何使用Flutter开发执行操作系统shell命令的工具

简介 Flutter是一种由Google开发的移动应用程序开发框架&#xff0c;它允许开发人员使用单个代码库构建高性能、高质量的移动体验。而Android终端命令行工具则允许用户在Android手机上运行类似于Linux的操作系统命令。本文的目的是介绍如何在Flutter应用中开发一个Android终端命…...

西山居 游戏研发工程师实习生 面经

西山居实习面经 面试时长&#xff1a;26min&#xff08;两个面试官交替问&#xff09; 1、自我介绍 2、你平常怎么学习的 3、你实习接受加班么 4、说一下Unity的生命周期&#xff0c;Start和Awake哪里不同 5、Unity中Update与FixedUpdate的区别&#xff0c;怎么设置Fixed…...

YOLOv8训练自己的数据集+改进方法复现

yolov8已经出来好几个月了&#xff0c;并且yolov8从刚开始出来之后的小版本也升级好几次&#xff0c;总体变化不大&#xff0c;个别文件存放位置发生了变化&#xff0c;以下以最新版本的YOLOv8来详细学习和使用YOLOv8完成一次目标检测。 一、环境按照 深度学习环境搭建就不再…...

尚硅谷kafka3.0.0

目录 &#x1f483;概述 ⛹定义 ​编辑⛹消息队列 &#x1f938;‍♂️消息队列应用场景 ​编辑&#x1f938;‍♂️两种模式&#xff1a;点对点、发布订阅 ​编辑⛹基本概念 &#x1f483;Kafka安装 ⛹ zookeeper安装 ⛹集群规划 ​编辑⛹流程 ⛹原神启动 &#x1f938;‍♂️…...

【Andriod】Appium的不同版本(Appium GUI、Appium Desktop、Appium Server )的安装教程

文章目录 前言一.Appium GUI二.Appium Desktop三.Appium Server 命令行版本1.安装node.js2.安装Appium Server 前言 Appium 安装提供两2方式&#xff1a;桌面版和命令行版。其中桌面版又分为 Appium GUI 和 Appium Desktop。 建议&#xff1a;使用Appium Desktop 一.Appium …...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...