深入解析C++五大常用设计模式:原理、实现与应用场景
设计模式是解决特定软件设计问题的经典方案,掌握它们能显著提升代码的可维护性和扩展性。本文详细解析C++中五种最常用的设计模式,附带完整代码示例和实战技巧。
一、设计模式概述
设计模式是面向对象编程中可复用的解决方案,它们源于工程师们多年积累的经验总结。在C++中应用设计模式能够:
-
提高代码复用性和扩展性
-
降低模块间的耦合度
-
提升系统的可维护性
-
使代码更符合开闭原则
下面我们将重点探讨五种最常用的设计模式及其C++实现。
二、工厂模式:对象创建的艺术
1. 简单工厂模式
// 抽象产品类
class Shape {
public:virtual void draw() = 0;virtual ~Shape() = default;
};// 具体产品类
class Circle : public Shape {
public:void draw() override { cout << "Drawing Circle" << endl; }
};class Rectangle : public Shape {
public:void draw() override { cout << "Drawing Rectangle" << endl; }
};// 简单工厂类
class ShapeFactory {
public:static Shape* createShape(const string& type) {if (type == "Circle") return new Circle();if (type == "Rectangle") return new Rectangle();return nullptr;}
};// 使用示例
int main() {Shape* circle = ShapeFactory::createShape("Circle");Shape* rect = ShapeFactory::createShape("Rectangle");circle->draw(); // Drawing Circlerect->draw(); // Drawing Rectangledelete circle;delete rect;
}
特点:
-
集中管理对象创建逻辑
-
客户端与具体类解耦
-
新增类型需修改工厂类(违反开闭原则)
2. 工厂方法模式
// 抽象工厂
class ShapeFactory {
public:virtual Shape* createShape() = 0;virtual ~ShapeFactory() = default;
};// 具体工厂
class CircleFactory : public ShapeFactory {
public:Shape* createShape() override { return new Circle(); }
};class RectangleFactory : public ShapeFactory {
public:Shape* createShape() override { return new Rectangle(); }
};// 使用示例
int main() {ShapeFactory* circleFactory = new CircleFactory();Shape* circle = circleFactory->createShape();circle->draw(); // Drawing Circledelete circle;delete circleFactory;
}
优势:
-
完全遵循开闭原则
-
每个产品对应独立工厂
-
支持多态性创建
三、单例模式:确保唯一实例
线程安全实现(C++11)
class Singleton {
private:Singleton() = default; // 私有构造函数~Singleton() = default; // 私有析构函数public:Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;static Singleton& getInstance() {static Singleton instance; // C++11保证线程安全return instance;}void showMessage() {cout << "Singleton instance working!" << endl;}
};// 使用示例
int main() {Singleton::getInstance().showMessage();
}
应用场景:
-
配置文件读取器
-
日志记录器
-
数据库连接池
-
线程池管理
四、观察者模式:状态变化的广播机制
#include <vector>
#include <algorithm>// 观察者接口
class Observer {
public:virtual void update(float temp) = 0;virtual ~Observer() = default;
};// 主题接口
class Subject {
private:vector<Observer*> observers;float temperature;public:void attach(Observer* obs) {observers.push_back(obs);}void detach(Observer* obs) {observers.erase(remove(observers.begin(), observers.end(), obs), observers.end());}void notify() {for (auto obs : observers) {obs->update(temperature);}}void setTemperature(float temp) {temperature = temp;notify();}
};// 具体观察者
class Display : public Observer {
public:void update(float temp) override {cout << "Temperature updated: " << temp << "°C" << endl;}
};// 使用示例
int main() {Subject weatherStation;Display display1, display2;weatherStation.attach(&display1);weatherStation.attach(&display2);weatherStation.setTemperature(25.5); // 所有显示器自动更新
}
模式结构:
Subject(主题)│├── attach(Observer)├── detach(Observer)└── notify()│▼Observer(观察者接口)▲││ConcreteObserver(具体观察者)
五、策略模式:算法的自由切换
// 策略接口
class SortingStrategy {
public:virtual void sort(vector<int>& data) = 0;virtual ~SortingStrategy() = default;
};// 具体策略
class BubbleSort : public SortingStrategy {
public:void sort(vector<int>& data) override {cout << "Using Bubble Sort" << endl;// 实现冒泡排序...}
};class QuickSort : public SortingStrategy {
public:void sort(vector<int>& data) override {cout << "Using Quick Sort" << endl;// 实现快速排序...}
};// 上下文类
class Sorter {
private:SortingStrategy* strategy;public:Sorter(SortingStrategy* strat = nullptr) : strategy(strat) {}void setStrategy(SortingStrategy* strat) {strategy = strat;}void executeSort(vector<int>& data) {if (strategy) strategy->sort(data);}
};// 使用示例
int main() {vector<int> data = {5, 2, 7, 1, 9};Sorter sorter;sorter.setStrategy(new BubbleSort());sorter.executeSort(data);sorter.setStrategy(new QuickSort());sorter.executeSort(data);
}
优势对比:
模式 | 优点 | 缺点 |
---|---|---|
工厂模式 | 解耦创建逻辑,代码复用 | 增加类数量 |
单例模式 | 全局唯一访问点,节省资源 | 测试困难,可能产生隐藏依赖 |
观察者模式 | 松耦合,动态订阅 | 通知顺序不可控 |
策略模式 | 算法自由切换,避免条件语句 | 客户端需了解策略差异 |
六、适配器模式:不兼容接口的桥梁
// 已有接口(不兼容)
class LegacyRectangle {
public:void draw(int x1, int y1, int x2, int y2) {cout << "LegacyRectangle: (" << x1 << "," << y1 << ") to (" << x2 << "," << y2 << ")" << endl;}
};// 目标接口
class Rectangle {
public:virtual void draw(int x, int y, int w, int h) = 0;virtual ~Rectangle() = default;
};// 适配器
class RectangleAdapter : public Rectangle {
private:LegacyRectangle legacyRect;public:void draw(int x, int y, int w, int h) override {// 转换参数调用旧接口legacyRect.draw(x, y, x + w, y + h);}
};// 使用示例
int main() {Rectangle* rect = new RectangleAdapter();rect->draw(10, 20, 30, 40); // 输出: LegacyRectangle: (10,20) to (40,60)
}
适用场景:
-
集成遗留代码
-
使用第三方库接口
-
统一多个类的接口
七、如何选择设计模式
-
创建型问题(对象创建)
-
工厂模式:需要统一管理创建逻辑
-
单例模式:要求全局唯一实例
-
-
结构型问题(对象组合)
-
适配器模式:接口转换需求
-
装饰器模式:动态添加功能
-
-
行为型问题(对象交互)
-
观察者模式:一对多状态通知
-
策略模式:算法灵活切换
-
黄金法则:不要为了用模式而用模式,当简单实现无法优雅解决问题时再考虑设计模式。
八、总结
设计模式是C++高级开发的必备技能,关键要点:
-
工厂模式解决对象创建问题
-
单例模式确保全局唯一访问
-
观察者模式实现松耦合通知
-
策略模式支持运行时算法切换
-
适配器模式解决接口兼容问题
最佳实践建议:
-
优先使用对象组合而非类继承
-
针对接口编程而非具体实现
-
遵循单一职责原则
-
小步重构引入模式,避免过度设计
掌握这些设计模式将显著提升你的C++架构设计能力。每种模式都有其适用场景,在实际项目中灵活组合使用,才能发挥最大价值。
相关文章:
深入解析C++五大常用设计模式:原理、实现与应用场景
设计模式是解决特定软件设计问题的经典方案,掌握它们能显著提升代码的可维护性和扩展性。本文详细解析C中五种最常用的设计模式,附带完整代码示例和实战技巧。 一、设计模式概述 设计模式是面向对象编程中可复用的解决方案,它们源于工程师们…...
标识符Symbol和迭代器的实现
Symbol基础 Symbol("描述") 创建唯一标识符(每次调用返回新值) Symbol.for("key") 全局注册表模式(相同key返回同一Symbol) Symbol特性 作为对象属性键时:obj[SymbolKey] value不参与常规遍历&…...

Appium+python自动化(九)- 定位元素工具
简介 环境搭建好了,其他方面的知识也准备的差不多了,那么就开始下一步元素定位,元素定位主要介绍如何使用uiautomatorviewer,通过定位到页面上的元素,然后进行相应的点击等操作. 此外在介绍另一款工具:Insp…...

Unity 中实现可翻页的 PageView
之前已经实现过: Unity 中实现可复用的 ListView-CSDN博客文章浏览阅读5.6k次,点赞2次,收藏27次。源码已放入我的 github,地址:Unity-ListView前言实现一个列表组件,表现方面最核心的部分就是重写布局&…...
clickhouse常用语句汇总——持续更新中
一、查询判断是否包含指定列 1.根据数据库,表名查看表包含的列 SELECT name FROM system.columns WHERE table table_name AND database databasename;2.查找指定列target_column是否是表table_name的列 SELECT count() > 0 AS column_exists FROM system…...

云计算 Linux Rocky day05【rpm、yum、history、date、du、zip、ln】
云计算 Linux Rocky day05【rpm、yum、history、date、du、zip、ln】 目录 云计算 Linux Rocky day05【rpm、yum、history、date、du、zip、ln】1.RPM包的一般安装位置2.软件名和软件包名3.查询软件信息4.查询软件包5.导入红帽签名信息,解决查询软件包信息报错6.利用…...

LuaJIT2.1 和 Lua5.4.8 性能对比
说明 最近在学习 LuaJIT,想看看把它接入到项目中使用,会提高多大的性能。 今天抽时间,简单地测试了一下 LuaJIT 2.2 和 Lua5.4.8 的性能。 测试平台: 系统:Windows 10 WSLCPU:Intel Core™ i7-8700 CPU…...
深度学习姿态估计实战:基于ONNX Runtime的YOLOv8 Pose部署全解析
本文将详细介绍如何脱离YOLO官方环境,使用ONNX Runtime部署YOLOv8姿态估计模型。内容包括模型加载、图像预处理(Letterbox缩放和填充)、推理执行、输出解码(边界框和关键点处理)、非极大值抑制(NMS…...
深度探索:如何用DeepSeek重构你的工作流
前言:AI时代的工作革命 在人工智能浪潮席卷的今天,DeepSeek作为国产大模型的代表之一,正以其强大的自然语言处理能力、代码生成能力和多模态交互特性,重新定义着人类的工作方式。根据IDC报告显示,2024年企业级AI应用市场规模已突破800亿美元,其中智能办公场景占比达32%,…...

深入解析与解决方案:处理Elasticsearch中all found copies are either stale or corrupt未分配分片问题
目录 引言 1 问题诊断深入分析 1.1 错误含义深度解析 1.2 获取详细的诊断信息 2 解决方案选择与决策流程 2.1 可用选项全面对比 2.2 推荐处理流程与决策树 3 具体操作步骤详解 3.1 优先尝试 - 分配最新副本(最低风险) 3.2 中等风险方案 - 分配…...

【NLP 78、手搓Transformer模型结构】
你以为走不出的淤泥,也迟早会云淡风轻 —— 25.5.31 引言 ——《Attention is all you need》 《Attention is all you need》这篇论文可以说是自然语言处理领域的一座里程碑,它提出的 Transformer 结构带来了一场技术革命。 研究背景与目标 在 Transfo…...
yum更换阿里云的镜像源
步骤 1:备份原有源配置(重要!) sudo mkdir /etc/yum.repos.d/backup sudo mv /etc/yum.repos.d/CentOS-* /etc/yum.repos.d/backup/步骤 2:下载阿里云源配置 sudo curl -o /etc/yum.repos.d/CentOS-Base.repo https:…...

如何自定义WordPress主题(5个分步教程)
如果您已经安装了一个 WordPress 主题,但它不太适合您,您可能会感到沮丧。在定制 WordPress 主题方面,您有很多选择。 挑战在于找到正确的方法。 在本篇文章中,我将引导您了解自定义 WordPress 主题的各种选项,帮助您…...
ios版本的Tiktok二次安装不上,提示:Unable to Install “TikTok”
问题:Domain: IXUserPresentableErrorDomain Code: 1 Recovery Suggestion: Failed to load Info.plist from bundle at path /private/var/containers/Bundle/Application/E99D86D4-F96E-48F9-86C5-FE095A22E13A/DouyinDev.app/PlugIns/AwemeNotificationService.a…...

react实现markdown文件预览
文章目录 react实现markdown文件预览1、实现md文件预览2、解决图片不显示3、实现效果 react实现markdown文件预览 1、实现md文件预览 1️⃣第一步:安装依赖: npm install react-markdown remark-gfmreact-markdown:将 Markdown 渲染为 Rea…...
Neo4j 认证与授权:原理、技术与最佳实践深度解析
Neo4j 作为领先的图数据库,其安全机制——认证(Authentication)与授权(Authorization)——是保障数据资产的核心防线。本文将深入剖析其工作原理、关键技术、实用技巧及行业最佳实践,助您构建坚不可摧的图数据安全体系。 Neo4j 提供了强大且灵活的认证授权框架,涵盖从基…...
Android Studio 配置之gitignore
1.创建或编辑.gitignore文件 在项目根目录下检查是否已有.gitignore文件。如果没有,创建一个新文件,命名为.gitignore(注意文件名前有个点)。 添加忽略规则:在.gitignore中添加以下内容: 忽略整个 .idea …...

PDF处理控件Aspose.PDF教程:在 C# 中更改 PDF 页面大小
PDF 的页面大小决定了其内容的显示、打印或处理方式。我们通常在准备打印、转换格式或标准化布局时需要更改 PDF 页面大小。在本文中,您将学习如何使用 C# 更改任何 PDF 文件的页面大小。我们将通过完整的代码示例,逐步指导您完成操作。 Aspose.PDF最新…...
Perl One-liner 数据处理——基础语法篇【匠心】
Perl(Practical Extraction and Report Language)是一种功能强大且灵活的脚本语言,因其强大的文本处理能力和简洁的语法而广受开发者和系统管理员的喜爱。特别是在命令行环境下,Perl 的 one-liner(单行脚本)以其高效、简洁的特点,成为数据处理、文本转换和快速原型设计的…...
PHP 打印扩展开发:从易联云到小鹅通的多驱动集成实践
目前已有易联云WIFI打印机扩展 扩展入口文件 文件目录 crmeb\services\printer\Printer.php namespace crmeb\services\printer;use crmeb\basic\BaseManager; use think\facade\Config; use think\Container;/*** Class Printer* package crmeb\services\auth* mixin \crme…...

rust或tauri项目执行命令的时候,cmd窗口也会弹出显示解决方法
阻止 Tauri 执行命令时弹出 CMD 窗口 当你在 Tauri 中使用 tokio::process::Command 执行命令时弹出 CMD 窗口,这是因为 Windows 默认会为控制台程序创建可见窗口。以下是几种解决方法: 1. 使用 Windows 特有的创建标志 (推荐) #[tauri::command] pub…...
[软件工程] 文档 | 技术文档撰写全流程指南
技术文档撰写全流程指南 一份优秀的技术文档需平衡 “技术严谨性” 与 “用户友好性”,其本质是降低信息传递成本,让读者能快速获取所需信息,减少沟通与试错成本。在实际操作中,从明确目标、结构化内容、可视化表达,到…...

使用Python进行函数作画
前言 因为之前通过deepseek绘制一下卡通的人物根本就不像,又想起来之前又大佬通过函数绘制了一些图像,想着能不能用Python来实现,结果发现可以,不过一些细节还是需要自己调整,deepseek整体的框架是没有问题࿰…...
Python应用continue关键字初解
大家好!对于刚接触编程的初学者来说,理解循环控制语句是掌握编程语言的重要一步。在Python中,continue关键字是一个非常实用的循环控制工具,本文将通过简易示例帮助大家理解它的作用。 基本概念: continue关键字用于中断本次循环,…...

微型导轨在手术机器人领域中有哪些关键操作?
在微创手术领域,手术机器人凭借其高精度、高稳定性和远程操控能力,正逐步成为现代外科手术的重要工具。微型导轨作为一种专为高精度运动设计的线性导向系统,凭借其亚微米级定位精度、低摩擦运动特性及紧凑结构设计,已成为手术机器…...

FPGA 的硬件结构
FPGA 的基本结构分为5 部分:可编程逻辑块(CLB)、输入/输出块(IOB)、逻辑块之间的布线资源、内嵌RAM 和内嵌的功能单元。 (1)可编程逻辑块(CLB) 一个基本的可编程逻辑块由…...

EasyRTC音视频实时通话助力新一代WebP2P视频物联网应用解决方案
一、方案背景 物联网技术深刻变革各行业,视频物联在智慧城市、工业监控等场景广泛应用。传统方案依赖中心服务器中转,存在传输效率低、网络负载大的问题。新一代WebP2P视频物联技术实现设备直连,降低网络压力并提升传输效率,成…...

QT开发技术【ffmpeg + QAudioOutput】音乐播放器 完善
一、完善上章的功能,形成一个小工具 QT开发技术【ffmpeg QAudioOutput】音乐播放器 二、增加歌曲保存类 #include "../Include/MusicListManager.h" #include "QtGui/Include/Conversion.h" #include <QFile> #include <QXmlStream…...

vscode 离线安装第三方库跳转库
我安装的是C/C的函数跳转 下载的离线库: 项目首页 - vscode代码自动补全跳转插件离线安装包:cpptools-win32.vsix是一款专为VSCode设计的离线安装插件,特别适合无法连接网络的电脑环境。通过安装此插件,您的VSCode将获得强大的代码自动跳转…...

DevExpress WinForms v24.2 - 新增日程组件、电子表格组件功能扩展
DevExpress WinForms拥有180组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜…...