【C++设计模式】开放-封闭原则
2023年8月27日,周日下午
我觉得我的这篇博客还是写得很不错的,哈哈哈。
目录
- 概述
- 举例说明
- 用开放-封闭原则重构
概述
开放-封闭原则(Open-Closed Principle,OCP)是面向对象设计中的一个重要原则,也是许多设计模式的基础。它由Bertrand Meyer在他的书《面向对象软件构造》中提出,并被广泛应用于软件开发中。
开放-封闭原则的核心思想是:软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。换句话说,当需要修改一个软件实体时,应该通过扩展它的行为,而不是修改它的源代码。
这个原则的目标是实现软件设计的稳定性和可维护性。通过遵循开放-封闭原则,我们可以减少修改已有代码的需求,从而降低了引入新错误的风险,并提高了代码的可复用性。
实现开放-封闭原则的关键是使用抽象和多态。通过定义抽象的接口或基类,可以将代码与特定的实现分离开来。这样,在需要变更行为时,我们只需要创建新的实现类并基于抽象进行扩展,而不需要修改已有的代码。
举例说明
假如有一天,公司要我写一个计算圆的面积的函数getArea
#include <iostream>// 计算圆的面积
double getArea(double radius) {return 3.14159 * radius * radius;
}int main() {// 计算面积double area = getArea(3);// 输出面积std::cout << "area: " << area << std::endl;return 0;
}
这很简单,是不是?
但是后来公司要求这个getArea函数要增加计算正方形的面积的功能,
假设我不懂开放-封闭原则,那么我只能老老实实修改getArea函数内部的代码
#include <iostream>// 计算面积
double getArea(double num,std::string thing) {if(thing=="圆形")return 3.14159 * num * num;if(thing=="正方形")return num*num;
}int main() {// 计算面积double area1 = getArea(3,"圆形");double area2=getArea(4,"正方形");// 输出面积std::cout << "圆形面积: " << area1 << std::endl;std::cout << "正方形面积: " << area2 << std::endl;return 0;
}
虽然我也完成了任务,但可以看到getArea函数变得复杂了:参数由1个变成2个;内部的实现代码也更多了。
但是任务还没结束,后来公司又让我给getArea函数添加计算长方形的功能
#include <iostream>// 计算面积
double getArea(double num1,double num2,std::string thing) {if(thing=="圆形")return 3.14159 * num1 * num1;if(thing=="正方形")return num1*num1;if(thing=="长方形")return num1*num2;
}int main() {// 计算面积double area1 = getArea(3,0,"圆形");double area2=getArea(4,0,"正方形");double area3=getArea(4,3,"长方形");// 输出面积std::cout << "圆形面积: " << area1 << std::endl;std::cout << "正方形面积: " << area2 << std::endl;std::cout << "长方形面积: " << area3 << std::endl;return 0;
}
可以看出来,我的getArea函数不仅变得更加难以理解,而且变得更加复杂了:参数由2个变成3个,而且内部代码实现也变多了。
接下来就不用写,照这么写下去,随着需求的增多,getArea函数只会变得越来越复杂和难以理解。
用开放-封闭原则重构
不难看出,在getArea中不变的是要返回一个面积,不断变化的是不同图形的计算方法,
所以可以封闭getArea的”返回一个面积“,而开放”计算方法“。
我把所有图形抽象成一个Shape抽象类,要求所有Shape抽象类的派生类都必须提供一个返回面积的接口。至于这些派生类怎么实现父类Shape要求的返回面积的接口,就各显神通、因地制宜了,此之谓”开放扩展“
而getArea函数只需雷打不动地调用Shape类的派生类的返回面积的接口就可以了,此之谓”封闭修改“。
#include <iostream>// 抽象基类,用于表示图形形状
class Shape {
public:virtual double area() const = 0;
};// 具体的图形形状:矩形
class Rectangle : public Shape {
public:double width;double height;Rectangle(double w, double h) : width(w), height(h) {}double area() const override {return width * height;}
};// 具体的图形形状:圆形
class Circle : public Shape {
public:double radius;Circle(double r) : radius(r) {}double area() const override {return 3.14159 * radius * radius;}
};// 计算所有图形的总面积
double getArea(const Shape* shape) {return shape->area();
}int main() {// 创建矩形和圆形对象Circle circle(3);Rectangle rect1(4, 4);Rectangle rect2(4, 3);// 计算总面积double area1 = getArea(&circle);double area2=getArea(&rect1);double area3=getArea(&rect2);// 输出面积std::cout << "圆形面积: " << area1 << std::endl;std::cout << "正方形面积: " << area2 << std::endl;std::cout << "长方形面积: " << area3 << std::endl;return 0;
}
可以看到,无论公司要求增加什么图形的计算面积功能,都不需要修改getArea函数,
只需要增加一个继承自Shape类的派生类就可以了,
不信的话,你们可以再添加一个计算梯形的面积试试,就当作一个小作业。
相关文章:
【C++设计模式】开放-封闭原则
2023年8月27日,周日下午 我觉得我的这篇博客还是写得很不错的,哈哈哈。 目录 概述举例说明用开放-封闭原则重构 概述 开放-封闭原则(Open-Closed Principle,OCP)是面向对象设计中的一个重要原则,也是许多…...
vue+file-saver+xlsx+htmlToPdf+jspdf实现本地导出PDF和Excel
页面效果如下(echarts图表按需添加,以下代码中没有) 1、安装插件 npm install xlsx --save npm install file-saver --save npm install html2canvas --save npm install jspdf --save2、main.js引入html2canvas import htmlToPdf from …...
axios 进阶
axios 进阶 接口传参方式 使用 xhr 原生技术或者是 axios 时,它的 post 传参方式是键值对的形式 keyvalue。但是在实际开发中一般是使用对象的形式定义数据,方便读取和赋值。所以当我们需要发起请求时可以通过 qs 这一款插件将对象转成键值对形式&…...
Redis限流实践:实现用户消息推送每天最多通知2次的功能
🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师…...
uniapp 存储base64资源为http链接图片
1. 新建一个base64.js 文件 const fsm wx.getFileSystemManager(); // base64data base64资源 // name 文件名 function base64src(base64data, name, cb) {const time new Date().getTime();const filePath ${wx.env.USER_DATA_PATH}/${name}.${time}.png;const buffer …...
列表类控件虚拟化
WPF列表控件提供的最重要的功能是UI虚拟化(WPF编程宝典说的)。所有的WPF列表控件(所有继承自ItemsControl的控件,包括ListBox、CombBox、ListView、TreeView、DataGrid)都支持UI虚拟化。 UI虚拟化的支持实际上没有被构…...
c# 多线程Task.Run 取消正在执行的多线程
c# 异步处理,上次处理没有完成,下次有紧接着处理多线程出错 在 C# 中进行异步处理时,确保处理上一个任务完成后再处理下一个任务是很重要的,特别是在涉及多线程的情况下。如果上一个任务尚未完成,而下一个任务又开始执…...
sql server 如何设置主键
开始之前 限制和局限 一个表只能包含一个 PRIMARY KEY 约束。 在 PRIMARY KEY 约束中定义的所有列都必须定义为 NOT NULL。 如果没有指定为 Null 性,则加入 PRIMARY KEY 约束的所有列的为 Null 性都将设置为 NOT NULL。 创建主键会自动创建相应的唯一群集索引、…...
【LeetCode-中等题】19. 删除链表的倒数第 N 个结点
文章目录 题目方法一:节点加入集合找索引方法二:直接计算长度,然后找出要删除的节点的前一个节点方法三:栈方法四:前后双指针 题目 这题的关键在与两个点 一定要设置一个哑结点,防止删除第一个元素时,导致空…...
Matlab图像处理-减法运算
减法运算 图像减法也称为差分方法,是一种常用于检测图像变化及运动物体的图像处理方法。常用来检测一系列相同场景图像的差异,其主要的应用在于检测同一场景下两幅图像之间的变化或是混合图像的分离。 差影法 将同一景物在不同时问拍摄的图像或同一景…...
stm32之11.USART串口通信
可以添加上拉电阻,但会增加功耗,传输距离变长 要添加库函数USART 官方参考文档说明书位置 ALT+左键可实现整体删除(如下图) 输出模式第三种模式AF ---------------------- 源码 远程控制pc端 #include <stm32f4x…...
Python实现T检验
今天来分享一下T检验的python实现方法。 01 先来上一波概念。 1.单样本t检验,又称单样本均数t检验,适用于来自正态分布的某个样本均数与已知总体均数的比较,其比较目的是检验样本均数所代表的总体均数是否与已知总体均数有差别。已知总体均数…...
校招算法题实在不会做,有没有关系?
文章目录 前言一、校招二、时间复杂度1、单层循环2、双层循环 三、空间复杂度四、数据结构五、校招算法题实在不会做,有没有关系?六、英雄算法集训 前言 英雄算法联盟八月集训 已经接近尾声,九月算法集训将于 09月01日 正式开始,目…...
Michael.W基于Foundry精读Openzeppelin第32期——SignatureChecker.sol
Michael.W基于Foundry精读Openzeppelin第32期——SignatureChecker.sol 0. 版本0.1 SignatureChecker.sol 1. 目标合约2. 代码精读2.1 isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) 0. 版本 [openzeppelin]:v4.8.3,[for…...
如何修改字符串内容?
⭐ 作者:小胡_不糊涂 🌱 作者主页:小胡_不糊涂的个人主页 📀 收录专栏:浅谈Java 💖 持续更文,关注博主少走弯路,谢谢大家支持 💖 String 1. 修改字符串2. StringBuilder和…...
pgadmin4中的备份与恢复
一,postgresql 数据的备份与恢复 (一)数据库备份与恢复 1,备份 windows环境 1> dump 逻辑备份 1,用管理员身份打开power shell 2,切换到本机 postgresql 安装目录下的 bin 目录: PS C…...
内网穿透——搭建私人影音媒体平台
文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及,各种各样的使用需求也被开发出来&…...
使用psql操作PostgreSQL数据库
postgresql的操作和mysql差别较大。。 可以使用 psql 命令行工具或者其他的 PostgreSQL 客户端工具来查看表。如下是使用 psql 命令行工具查看表的方法: 连接到 PostgreSQL 数据库: 如果一个PostgreSQL的连接为 postgresql://用户名:密码127.0.0.1:5432/…...
什么是网络取证(Network Forensics)
企业采用新技术来检查其网络安全是否存在零日漏洞,与立即指示问题的物理层不同,黑客攻击尝试可能会被忽视并变得严重,直到对网络流量有一个整体的可见性。通过实时监控来跟踪其源和目标的流量,以查明问题或潜在问题的根源。 什么…...
农村农产品信息展示网站的设计与实现(论文+源码)_kaic
摘 要 随着软件技术的迅速发展,农产品信息展示的平台越来越多,传统的农产品显示方法将被计算机图形技术取代。这种网站技术主要把农产品的描述、农产品价格、农产品图片等内容,通过计算机网络的开发技术,在互联网上进行展示,然后通过计算机网…...
国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
