设计模式C++
针对一些经典的常见的场景, 给定了一些对应的解决方案,这个就叫设计模式。
设计模式的作用:使代码的可重用性高,可读性强,灵活性好,可维护性强。
设计原则:
单一职责原则:一个类只做一方面的事。
开闭原则:以前写过的代码不能动,修改以前写的代码是非常危险的事情,我们可以在原来的基础上进行扩展,例如添加新的方法。
接口隔离原则:接口定义的功能尽量少,不要包含太多的功能。
里氏替换原则:在继承关系的代码开发中,如果需要进行功能的扩展,不要在子类中改变父类中已经实现的方法,而是通过新增方法来扩展父类的功能。
依赖倒置原则:在定义类的成员变量,参数类型,返回值类型的时候,不要写某个具体的实现类,而是尽量采用接口或者抽象类,这样后续如果我们想改,不需要改动代码,只需要增加实现类就可以了。
创建型模式:
创建型模式:用于解耦对象实例化的过程。
工厂模式:
工厂模式的思想是将对象的创建逻辑封装到一个专门的类中,客户端无需直接 new 具体类,从而降低代码耦合。
当对象创建逻辑复杂,或需要统一管理创建过程时使用工厂模式。
#include <iostream>// 抽象产品类(接口)
class Shape {
public:virtual void draw() = 0;virtual ~Shape() {} // 虚析构,确保正确释放子类对象
};// 具体产品类:圆形
class Circle : public Shape {
public:void draw() override {std::cout << "Drawing a Circle" << std::endl;}
};// 具体产品类:方形
class Square : public Shape {
public:void draw() override {std::cout << "Drawing a Square" << std::endl;}
};
简单工厂模式:
定义抽象产品类,具体产品类,工厂类,用户不必知道创建对象的细节,只需要调用工厂类(静态创建对象函数)。(针对单一产品)
违反了开闭原则,新增产品类需要修改工厂类的代码。
// 工厂类
class ShapeFactory {
public:// 根据类型创建对象(静态方法)static Shape* createShape(const std::string& type) {if (type == "Circle") {return new Circle();} else if (type == "Square") {return new Square();}return nullptr; // 无效类型返回空}
};// 客户端代码
int main() {// 通过工厂创建对象Shape* circle = ShapeFactory::createShape("Circle");Shape* square = ShapeFactory::createShape("Square");circle->draw(); // 输出: Drawing a Circlesquare->draw(); // 输出: Drawing a Squaredelete circle;delete square;return 0;
}
工厂方法模式:
创建抽象工厂类,每一个产品对应一个产品工厂。
// 抽象工厂
class ShapeFactory {
public:virtual Shape* createShape() = 0;virtual ~ShapeFactory() {}
};// 圆形工厂
class CircleFactory : public ShapeFactory {
public:Shape* createShape() override {return new Circle();}
};// 方形工厂
class SquareFactory : public ShapeFactory {
public:Shape* createShape() override {return new Square();}
};// 客户端使用
ShapeFactory* factory = new CircleFactory();
Shape* shape = factory->createShape();
抽象工厂模式:
针对 多个产品族 的创建

#include <iostream>// ----------------- 抽象产品接口 -----------------
// 抽象按钮
class Button {
public:virtual void render() = 0;virtual ~Button() {}
};// 抽象复选框
class Checkbox {
public:virtual void check() = 0;virtual ~Checkbox() {}
};// ----------------- 具体产品实现 -----------------
// Windows 按钮
class WindowsButton : public Button {
public:void render() override {std::cout << "Windows 风格按钮渲染" << std::endl;}
};// Windows 复选框
class WindowsCheckbox : public Checkbox {
public:void check() override {std::cout << "Windows 复选框被勾选" << std::endl;}
};// Mac 按钮
class MacButton : public Button {
public:void render() override {std::cout << "Mac 风格按钮渲染" << std::endl;}
};// Mac 复选框
class MacCheckbox : public Checkbox {
public:void check() override {std::cout << "Mac 复选框被勾选" << std::endl;}
};// ----------------- 抽象工厂接口 -----------------
class GUIFactory {
public:virtual Button* createButton() = 0;virtual Checkbox* createCheckbox() = 0;virtual ~GUIFactory() {}
};// ----------------- 具体工厂实现 -----------------
class WindowsFactory : public GUIFactory {
public:Button* createButton() override {return new WindowsButton();}Checkbox* createCheckbox() override {return new WindowsCheckbox();}
};class MacFactory : public GUIFactory {
public:Button* createButton() override {return new MacButton();}Checkbox* createCheckbox() override {return new MacCheckbox();}
};// ----------------- 客户端代码 -----------------
int main() {// 假设根据当前系统选择工厂GUIFactory* factory;// 模拟配置:选择 Windows 或 Mac 工厂std::string os = "Windows";if (os == "Windows") {factory = new WindowsFactory();} else {factory = new MacFactory();}// 使用工厂创建一组组件Button* button = factory->createButton();Checkbox* checkbox = factory->createCheckbox();button->render(); // 输出对应系统的按钮渲染checkbox->check(); // 输出对应系统的复选框行为delete factory;delete button;delete checkbox;return 0;
}
简单工厂 vs 工厂方法 vs 抽象工厂?
-
简单工厂:一个工厂类负责所有产品。
-
工厂方法:每个产品对应一个工厂子类。
-
抽象工厂:生产一个产品家族(例如不同风格的 UI 组件)。
单例模式:
单例设计模式(Singleton Pattern) 是一种创建型设计模式,用于确保一个类只有一个实例,并提供一个全局访问点来访问该实例。单例模式无法被回收,他的生命周期随进程,可以手动释放或者使用智能指针进行管理。
饿汉模式
饿汉模式:饿汉非常简单,定义静态实例,静态方法在加载到内存时就全部加载出来,缺陷是如果很大启动时就会花很长时间。
class Singleton {
private:static Singleton instance; // 静态实例Singleton() {} // 私有构造函数// 禁止拷贝构造函数和赋值操作符,防止拷贝Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;public:static Singleton* getInstance() {return &instance; // 直接返回静态实例的地址}
};// 在类外部初始化静态实例
Singleton Singleton::instance;
懒汉模式
懒汉模式:懒汉的核心思想是“延迟加载”,使用时再创建实例,使用双重检查锁确保线程安全和同步开销。
#include <mutex>class Singleton {
private:static Singleton* instance; // 静态实例指针static std::mutex mutex; // 互斥锁,用于线程同步Singleton() {} // 私有构造函数// 禁止拷贝构造函数和赋值操作符,防止拷贝Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;public:static Singleton* getInstance() {if (instance == nullptr) { // 双重检查锁定(Double-Checked Locking)std::lock_guard<std::mutex> lock(mutex); // 加锁if (instance == nullptr) { // 再次检查实例是否已创建instance = new Singleton(); // 如果未创建,则创建实例}}return instance; // 返回实例的地址}
};// 在类外部初始化静态实例指针和互斥锁
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;
Meyer's Singleton
使用静态局部变量实现的单例模式。静态局部变量的初始化是线程安全的。编译器会确保静态局部变量只被初始化一次,即使多个线程同时调用 getInstance()。同时避免了资源浪费。实现简单,是现代 C++ 中推荐的单例实现方式。
class Singleton {
private:Singleton() {} // 私有构造函数Singleton(const Singleton&) = delete; // 禁止拷贝构造Singleton& operator=(const Singleton&) = delete; // 禁止赋值操作public:static Singleton& getInstance() {static Singleton instance; // 静态局部变量return instance;}void doSomething() {std::cout << "Singleton is doing something!" << std::endl;}
};
应用场景:
线程池,内存池
结构型模式:
结构型模式:把类和对象结合在一起形成一个更大的结构。
行为型模式:
行为性模式:类和对象如何交互,划分责任和算法。
策略模式:
允许使用者根据不同的情况选择不同的策略(算法或行为)执行。
-
抽象策略接口(
SortStrategy)
定义所有具体策略必须实现的方法(如sort())。 -
具体策略类(
BubbleSort、QuickSort)
实现具体的算法逻辑。 -
上下文类(
Sorter)-
持有策略对象的引用(通过组合关系)。
-
提供设置策略的方法(
setStrategy())和执行策略的方法(executeSort())。
-
#include <iostream>
#include <vector>
#include <memory>// ----------------- 1. 抽象策略接口 -----------------
class SortStrategy {
public:virtual void sort(std::vector<int>& data) = 0;virtual ~SortStrategy() {} // 虚析构确保正确释放资源
};// ----------------- 2. 具体策略类 -----------------
// 冒泡排序策略
class BubbleSort : public SortStrategy {
public:void sort(std::vector<int>& data) override {std::cout << "使用冒泡排序" << std::endl;// 实现冒泡排序逻辑...}
};// 快速排序策略
class QuickSort : public SortStrategy {
public:void sort(std::vector<int>& data) override {std::cout << "使用快速排序" << std::endl;// 实现快速排序逻辑...}
};// ----------------- 3. 上下文类(Context) -----------------
class Sorter {
private:std::unique_ptr<SortStrategy> strategy; // 使用智能指针管理策略对象public:// 设置策略void setStrategy(std::unique_ptr<SortStrategy> newStrategy) {strategy = std::move(newStrategy);}// 执行排序void executeSort(std::vector<int>& data) {if (strategy) {strategy->sort(data);} else {std::cout << "未设置排序策略!" << std::endl;}}
};// ----------------- 客户端代码 -----------------
int main() {Sorter sorter;std::vector<int> data = {5, 2, 7, 1, 3};// 动态切换策略sorter.setStrategy(std::make_unique<BubbleSort>());sorter.executeSort(data); // 输出:使用冒泡排序sorter.setStrategy(std::make_unique<QuickSort>());sorter.executeSort(data); // 输出:使用快速排序return 0;
}
应用场景:
游戏中的角色行为:角色根据状态切换攻击、防御、逃跑策略。
动态使用不同的算法。
观察者模式:
定义对象间的一对多依赖关系,当一个对象(主题)状态改变时,所有依赖它的对象(观察者)会自动收到通知并更新。
应用场景:订阅-通知机制,实现松耦合的一对多事件处理。比如气象观测,观测机器观察到了数据,通知各类的软件。
中介者模式:
用一个中介对象(Mediator)来封装一组对象(Colleague)之间的交互,从而减少对象间的直接耦合。所有对象通过中介者通信,而不是直接相互引用。
应用场景:聊天室
模版模式:
在父类中定义一个规定了算法的执行步骤和顺序的模板方法,声明为 final,再将算法中的步骤声明为抽象方法或虚函数,由子类具体实现。
#include <iostream>// 抽象基类:定义饮料制作的模板
class Beverage {
public:// 模板方法(final 禁止子类修改流程)void prepareBeverage() final {boilWater();brew();addCondiments();pourInCup();}protected:// 具体步骤由子类实现virtual void brew() = 0;virtual void addCondiments() = 0;// 公共步骤(直接复用)void boilWater() {std::cout << "煮沸水" << std::endl;}void pourInCup() {std::cout << "倒入杯子" << std::endl;}virtual ~Beverage() = default;
};// 具体子类:咖啡
class Coffee : public Beverage {
protected:void brew() override {std::cout << "冲泡咖啡粉" << std::endl;}void addCondiments() override {std::cout << "加糖和牛奶" << std::endl;}
};// 具体子类:茶
class Tea : public Beverage {
protected:void brew() override {std::cout << "浸泡茶叶" << std::endl;}void addCondiments() override {std::cout << "加柠檬" << std::endl;}
};// 客户端代码
int main() {Beverage* coffee = new Coffee();coffee->prepareBeverage();// 输出:// 煮沸水// 冲泡咖啡粉// 加糖和牛奶// 倒入杯子Beverage* tea = new Tea();tea->prepareBeverage();// 输出:// 煮沸水// 浸泡茶叶// 加柠檬// 倒入杯子delete coffee;delete tea;return 0;
}
应用场景:
比如餐厅服务员的游戏,制作可乐,雪碧什么的饮料都是一样的步骤,就可以设定一个制作饮料的类,里面规定制作饮料的步骤。
相关文章:
设计模式C++
针对一些经典的常见的场景, 给定了一些对应的解决方案,这个就叫设计模式。 设计模式的作用:使代码的可重用性高,可读性强,灵活性好,可维护性强。 设计原则: 单一职责原则:一个类只做一方面的…...
前端构建工具进化论:从Grunt到Turbopack的十年征程
前端构建工具进化论:从Grunt到Turbopack的十年征程 一、石器时代:任务自动化工具(2012-2014) 1.1 Grunt:首个主流构建工具 // Gruntfile.js 典型配置 module.exports function(grunt) {grunt.initConfig({concat: {…...
设备预测性维护:企业降本增效的关键密码
在当今竞争激烈的商业战场中,企业犹如一艘在波涛汹涌大海上航行的巨轮,要想乘风破浪、稳步前行,降本增效便是那至关重要的 “船锚”,帮助企业在复杂的市场环境中站稳脚跟。而设备预测性维护,正是开启企业降本增效大门的…...
css基本功
为什么 ::first-letter 是伪元素? ::first-letter 的作用是选择并样式化元素的第一个字母,它创建了一个虚拟的元素来包裹这个字母,因此属于伪元素。 grid布局 案例一 <!DOCTYPE html> <html lang"zh-CN"><head&…...
信号处理抽取多项滤波的数学推导与仿真
昨天的《信号处理之插值、抽取与多项滤波》,已经介绍了插值抽取的多项滤率,今天详细介绍多项滤波的数学推导,并附上实战仿真代码。 一、数学变换推导 1. 多相分解的核心思想 将FIR滤波器的系数 h ( n ) h(n) h(n)按相位分组,每…...
C++双端队列知识点+习题
在C中,双端队列(Deque,发音为“deck”)是标准模板库(STL)中的一种容器适配器,其全称为Double-Ended Queue。它结合了队列和栈的特点,允许在容器的两端(前端和后端&#x…...
【递归、搜索和回溯算法】专题二 :二叉树中的深搜
二叉树中的深搜 深度优先遍历(DFS):一种沿着树或图的深度遍历节点的算法,尽可能深地搜索树或图的分支,如果一条路径上的所有结点都被遍历完毕,就会回溯到上一层,继续找一条路遍历。 在二叉树中…...
Vue3计算属性深度解析:经典场景与Vue2对比
一、计算属性的核心价值 计算属性(Computed Properties)是Vue响应式系统的核心特性之一,它通过依赖追踪和缓存机制优雅地解决模板中复杂逻辑的问题。当我们需要基于现有响应式数据进行派生计算时,计算属性总能保持高效的性能表现…...
UE5与U3D引擎对比分析
Unreal Engine 5(UE5)和Unity 3D(U3D)是两款主流的游戏引擎,适用于不同类型的项目开发。以下是它们的主要区别,分点整理: 1. 核心定位 UE5: 主打3A级高画质项目(如主机/P…...
【vue3学习笔记】(第150-151节)computed计算属性;watch监视ref定义的数据
尚硅谷Vue2.0Vue3.0全套教程丨vuejs从入门到精通 本篇内容对应课程第150-151节 课程 P150节 《computed计算属性》笔记 写一个简单的 姓、名输入框效果: 用vue2的形式定义一个计算属性 fullName: 测试页面展示无问题: 但是,在vue…...
JavaScript如何实现复制图片功能?
最近开发中遇到一个需求,就是用户希望能通过直接点击按钮复制图片,然后就可以很方便的把图片发送到班群中,于是就有了复制图片的需求。 那么如何通过JavaScript来实现复制图片呢? 一、前置知识:如何实现复制…...
MySQL 8 设置允许远程连接(Windows环境)
🌟 MySQL 8 设置允许远程连接(Windows环境) 在开发和部署应用时,经常需要从远程主机连接到MySQL数据库。默认情况下,MySQL仅允许本地连接,因此需要进行一些配置才能允许远程访问。今天,我将详细…...
我又又又又又又更新了~~纯手工编写C++画图,有注释~~~
再再再次感谢Ttcofee提的问题 本次更新内容: 鼠标图案(切换),版本号获取,输入框复制剪切板 提前申明:如果运行不了,请到主页查看RedpandaDevc下载,若还是不行就卸了重装。 版本号&…...
Python控制语句——循环语句-for
1.下面的语句哪个会无限循环下去()。 A、 for a in range(10): time.sleep(10) B、 while 1<10: time.sleep(10) C、 while True: break D、 a = [3,-1,2] for i in a: if i==-1: break 答案:B。1<10始终为True,循环体中又没有break的条件,故B会无限循环。 2.for s i…...
全面解析:将采购入库单数据集成到MySQL的技术实施
旺店通旗舰版-采购入库单集成到MySQL的技术案例分享 在数据驱动的业务环境中,如何高效、准确地实现系统间的数据对接是企业面临的重要挑战。本文将聚焦于一个具体的系统对接集成案例:将旺店通旗舰奇门平台上的采购入库单数据集成到MySQL数据库中&#x…...
12. Pandas :使用pandas读Excel文件的常用方法
一 read_excel 函数 其他参数根据实际需要进行查找。 1.接受一个工作表 在 11 案例用到的 Excel 工作簿中,数据是从第一张工作表的 A1 单元格开始的。但在实际场景中, Excel 文件可能并没有这么规整。所以 panda 提供了一些参数来优化读取过程。 比如 s…...
记录致远OA服务器硬盘升级过程
前言 日常使用中OA系统突然卡死,刷新访问进不去系统,ping服务器地址正常,立马登录服务器检查,一看磁盘爆了。 我大脑直接萎缩了,谁家OA系统配400G的空间啊,过我手的服务器没有50也是30台,还是…...
Java网络多线程
网络相关概念: 关于访问: IP端口 因为一个主机上可能有多个服务, 一个服务监听一个端口,当你访问的时候主机通过端口号就能知道要和哪个端口发生通讯.因此一个主机上不能有两个及以上的服务监听同一个端口. 协议简单来说就是数据的组织形式 好像是两个人交流一样,要保证自己说…...
【H2O2 | 软件开发】Axios发送Http请求
目录 前言 开篇语 准备工作 正文 概念 封装工具包 示例 结束语 前言 开篇语 本系列为短篇,每次讲述少量知识点,无需一次性灌输太多的新知识点。该主题文章主要是围绕前端、全栈开发相关面试常见问题撰写的,希望对诸位有所帮助。 如…...
VScode 运行LVGL
下载vscode解压 环境安装 安装mingw64,gcc 版本必须8.3以上 安装cmak 系统环境变量Path中添加(以实际安装目录为准) C:\Program Files\mingw64\bin C:\Program Files\CMake\bin 将GUI-Guider生成的代码目录拷贝一份放到vscode项目目录…...
AIP-165 按条件删除
编号165原文链接https://google.aip.dev/165状态批准创建日期2019-12-18更新日期2019-12-18 有时API需要提供一种机制,按照一些过滤参数删除大量资源,而非提供待删除的各资源名字。 这是一个稀有的场景,用于用户一次性删除数千或更多资源的…...
React Next项目中导入Echart世界航线图 并配置中文
公司业务要求做世界航线图,跑了三个ai未果,主要是引入world.json失败,echart包中并不携带该文件,源码的world.json文件页面404找不到。需要自己寻找。这是整个问题卡壳的关键点,特此贴出资源网址。 目录 一、安装 二…...
QT与网页显示数据公式的方法
一.网页中显示数学公式通常有三种主要方法 1.图片方式 原理:将公式转换为图片(如 PNG、SVG),通过 <img> 标签嵌入网页。 实现步骤: 使用工具(如 LaTeX dvipng、在线生成工具)将公式渲…...
深入解析APP订阅页的运作机制(订阅页如何运作)
在当今数字经济的背景下,订阅模式已成为许多企业获取稳定收入的重要方式。无论是软件、视频流媒体还是电子商务,订阅服务都能为用户提供持续的价值体验。然而,如何有效地设计和运作一个订阅页,是决定用户是否愿意订阅的关键因素。…...
Golang倒腾一款简配的具有请求排队功能的并发受限服务器
golang官方指南[1]给了一些代码片段,层层递进演示了信道的能力: 1>. 信号量2>. 限流能力 var sem make(chan int, MaxOutstanding) func Serve(queue chan *Request) {for req : range queue {req: reqsem <- 1 go func() { // 只会开启MaxOutstandin…...
【运维】服务器系统从centos7重装为ubuntu22.04
目录 一、硬盘准备二、系统安装三、安装基本系统组件四、挂载机械硬盘五、问题解决 一、硬盘准备 【注意:这一步会把硬盘的数据清空,所以需要找一个空的U盘或者把U盘数据备份】 ubuntu22.04下载 需要先安装 bittorrent 下载完之后会打开一个网页 然后…...
创新技术引领软件供应链安全,助力数字中国建设
编者按 随着数字化转型的加速,针对软件供应链的攻击事件呈快速增长态势,目前已成为网络空间安全的焦点。如何将安全嵌入到软件开发到运营的全流程,实现防护技术的自动化、一体化、智能化,成为技术领域追逐的热点。 悬镜安全作为…...
【设计模式】建造者模式——工厂模式
三、建造者模式——工厂模式 3.1 工厂模式 创建一个类对象的传统方式是使用关键字new, 因为用new 创建的类对象是一个堆对象,可以实现多态。工厂模式通过把创建对象的代码包装起来,实现创建对象的代码与具体 的业务逻辑代码相隔离的目的(将对象的创建和…...
Java基础:枚举类enum入门案例
1.基础枚举定义与使用: package com.zxy;public class Main {public static void main(String[] args) { // 获取枚举值cars car cars.BMW;switch (car){case BMW :System.out.println("BMW");break;case BENZ :System.out.println("BENZ&…...
蓝桥备赛(18)- 红黑树和 set 与 map(上)
对于二叉搜索树 , 平衡二叉树 , 以及红黑树 , 目前只需要了解背后的原理 , 不做代码实现的要求 , 重要的就是了解各种操作的时间复杂度即可 , 为set 与 map 做铺垫 一、二叉搜索树 1.1 基本概念 相较与于堆…...
