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

工程实践中常见的几种设计模式解析及 C++ 实现

工程实践中常见的几种设计模式解析及 C++ 实现

在软件工程中,设计模式是一种通用的解决方案,用于解决常见问题和优化代码结构。它们通过提供一种规范化的编程思想,帮助开发者写出更高效、可维护和可扩展的代码。本文将介绍几种在工程实践中常见的设计模式,包括其实现原理、使用场景以及注意事项,并结合 C++ 语言进行实现。


1. 单例模式 (Singleton Pattern)

实现原理

单例模式确保一个类只有一个实例,并提供全局访问点。其核心思想是通过控制构造函数和复制操作符,使得类只能生成一个对象实例。

关键点:
  • 隐藏构造函数(将构造函数设为私有)。
  • 提供一个静态方法用于获取唯一实例。
  • 使用懒汉式或饿汉式实现线程安全的单例模式。

使用场景

  • 当需要全局只有一个实例时,例如配置管理、日志记录等。
  • 需要避免大量重复对象创建的情况。

注意事项

  • 单例模式可能会隐藏类之间的依赖关系,导致代码难以维护。
  • 线程安全性需要额外处理(如双重检查锁定)。
  • 在某些场景下,单例模式可能导致性能问题或内存泄漏。
C++ 实现
class Singleton {
private:static Singleton* instance;Singleton() = default;  // 隐藏构造函数~Singleton() = default; // 隐藏析构函数public:// 静态方法获取实例(线程安全)static Singleton* getInstance() {if (instance == nullptr) {instance = new Singleton();}return instance;}// 删除复制操作符,防止复制Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;void doSomething() {// 业务逻辑}
};// 静态变量初始化为 nullptr
Singleton* Singleton::instance = nullptr;int main() {Singleton* s1 = Singleton::getInstance();Singleton* s2 = Singleton::getInstance();if (s1 == s2) { // 比较两个指针是否相同// 输出:两者指向同一个实例}return 0;
}

2. 工厂模式 (Factory Pattern)

实现原理

工厂模式通过提供一个接口,用于创建对象,而无需显式指定具体类。这提高了代码的灵活性和可扩展性。

关键点:
  • 定义一个抽象产品类(Product)。
  • 提供一个工厂类(Factory),通过其方法创建具体的子类实例。
  • 工厂模式分为简单工厂模式和抽象工厂模式。

使用场景

  • 需要根据不同的条件动态选择具体实现时。
  • 避免代码直接依赖于具体实现类,提高系统的灵活性。

注意事项

  • 工厂类可能会变得复杂,尤其是在支持多种产品的情况下。
  • 增加新的产品类需要同时修改工厂类,这可能违反“开闭原则”。
C++ 实现
// 抽象产品类
class Product {
public:virtual ~Product() = default;virtual void use() = 0;
};// 具体产品类
class ConcreteProductA : public Product {
public:void use() override {// 使用具体实现 A}
};class ConcreteProductB : public Product {
public:void use() override {// 使用具体实现 B}
};// 工厂类
class Factory {
public:virtual ~Factory() = default;virtual std::unique_ptr<Product> createProduct() = 0;
};// 具体工厂类 A
class ConcreteFactoryA : public Factory {
public:std::unique_ptr<Product> createProduct() override {return std::make_unique<ConcreteProductA>();}
};// 具体工厂类 B
class ConcreteFactoryB : public Factory {
public:std::unique_ptr<Product> createProduct() override {return std::make_unique<ConcreteProductB>();}
};int main() {// 使用工厂创建产品Factory* factory = new ConcreteFactoryA();auto product = factory->createProduct();product->use();delete factory;return 0;
}

3. 观察者模式 (Observer Pattern)

实现原理

观察者模式定义了一种一对多的依赖关系,当一个对象(主题)的状态发生变化时,所有依赖它的对象(观察者)都会收到通知并自动更新。

关键点:
  • 定义一个主题类(Subject),包含状态和注册/注销观察者的接口。
  • 观察者类(Observer)通过继承或实现接口,提供一个更新方法。
  • 主题类维护一个观察者列表,并在状态变化时通知所有观察者。

使用场景

  • 系统中存在一对多的依赖关系时。
  • 需要动态地添加或删除观察者。

注意事项

  • 观察者模式可能会导致循环依赖问题。
  • 观察者和主题之间的耦合可能会影响代码的可维护性。
C++ 实现
#include <vector>
#include <memory>class Observer {
public:virtual ~Observer() = default;virtual void update(int value) = 0;
};class Subject {
private:int state_;std::vector<std::shared_ptr<Observer>> observers_;public:void attach(std::shared_ptr<Observer> observer) {observers_.push_back(observer);}void detach(std::shared_ptr<Observer> observer) {// 实现观察者的移除逻辑}int getState() const {return state_;}void setState(int value) {if (state_ != value) {state_ = value;notify();}}private:void notify() {for (auto& observer : observers_) {observer->update(state_);}}
};class ConcreteObserver : public Observer {
public:void update(int value) override {// 处理状态变化}
};int main() {std::shared_ptr<Subject> subject = std::make_shared<Subject>();std::shared_ptr<ConcreteObserver> observer1 = std::make_shared<ConcreteObserver>();std::shared_ptr<ConcreteObserver> observer2 = std::make_shared<ConcreteObserver>();subject->attach(observer1);subject->attach(observer2);subject->setState(10); // 所有观察者都会收到更新return 0;
}

4. 策略模式 (Strategy Pattern)

实现原理

策略模式定义了一系列算法,并将它们封装起来,使它们可以互换。上下文类通过接口调用具体策略类的方法。

关键点:
  • 定义一个策略接口(Strategy),包含算法的声明。
  • 具体策略类(Concrete Strategy)实现策略接口。
  • 上下文类(Context)维护一个策略对象,并根据需要切换策略。

使用场景

  • 需要动态选择不同算法时。
  • 系统中存在多个相似但具体的算法,且希望它们可以互换使用。

注意事项

  • 增加新的具体策略类可能会影响上下文的代码复杂性。
  • 必须确保所有策略接口的一致性。
C++ 实现
class Strategy {
public:virtual ~Strategy() = default;virtual int calculate(int a, int b) = 0;
};// 具体策略类 A:加法
class AddStrategy : public Strategy {
public:int calculate(int a, int b) override {return a + b;}
};// 具体策略类 B:乘法
class MultiplyStrategy : public Strategy {
public:int calculate(int a, int b) override {return a * b;}
};// 上下文类
class Context {
private:std::shared_ptr<Strategy> strategy_;public:Context(std::shared_ptr<Strategy> strategy) : strategy_(strategy) {}void setStrategy(std::shared_ptr<Strategy> strategy) {strategy_ = strategy;}int execute(int a, int b) {return strategy_->calculate(a, b);}
};int main() {std::shared_ptr<Context> context = std::make_shared<Context>(std::make_shared<AddStrategy>());// 使用加法策略int result1 = context->execute(3, 5); // 8// 切换到乘法策略context->setStrategy(std::make_shared<MultiplyStrategy>());int result2 = context->execute(3, 5); // 15return 0;
}

总结

以上四种设计模式(单例模式、工厂模式、观察者模式和策略模式)是工程实践中最常用的设计模式之一。每种模式都有其适用的场景和注意事项,合理使用它们可以显著提升代码的质量和系统的可维护性。

在实际开发中,我们需要根据具体需求选择合适的设计模式,并结合语言特性和框架进行实现。同时,也要注意避免过度设计,以免增加不必要的复杂性。

相关文章:

工程实践中常见的几种设计模式解析及 C++ 实现

工程实践中常见的几种设计模式解析及 C 实现 在软件工程中&#xff0c;设计模式是一种通用的解决方案&#xff0c;用于解决常见问题和优化代码结构。它们通过提供一种规范化的编程思想&#xff0c;帮助开发者写出更高效、可维护和可扩展的代码。本文将介绍几种在工程实践中常见…...

基于Python+django+mysql旅游数据爬虫采集可视化分析推荐系统

2024旅游推荐系统爬虫可视化&#xff08;协同过滤算法&#xff09; 基于Pythondjangomysql旅游数据爬虫采集可视化分析推荐系统 有文档说明 部署文档 视频讲解 ✅️基于用户的协同过滤推荐算法 卖价就是标价~ 项目技术栈 Python语言、Django框架、MySQL数据库、requests网络爬虫…...

Oracle 12c Docker安装问题排查 sga_target 1536M is too small

一、问题描述 在虚拟机环境&#xff08;4核16GB内存&#xff09;上部署 truevoly/oracle-12c 容器镜像时&#xff0c;一切运行正常。然而&#xff0c;当在一台 128 核 CPU 和 512GB 内存的物理服务器上运行时&#xff0c;容器启动时出现了 ORA-00821 等错误&#xff0c;提示 S…...

es-head(es库-谷歌浏览器插件)

1.下载es-head插件压缩包&#xff0c;并解压缩 2.谷歌浏览器添加插件 3.使用...

C++大整数类的设计与实现

1. 简介 我们知道现代的计算机大多数都是64位的&#xff0c;因此能处理最大整数为 2 64 − 1 2^{64}-1 264−1。那如果是超过了这个数怎么办呢&#xff0c;那就需要我们自己手动模拟数的加减乘除了。 2. 思路 我们可以用一个数组来存储大数&#xff0c;数组中的每一个位置表…...

Linux网络基础(协议 TCP/IP 网络传输基本流程 IP VS Mac Socket编程UDP)

文章目录 一.前言二.协议协议分层分层的好处 OSI七层模型TCP/IP五层(或四层)模型为什么要有TCP/IP协议TCP/IP协议与操作系统的关系(宏观上是如何实现的)什么是协议 三.网络传输基本流程局域网(以太网为例)通信原理MAC地址令牌环网 封装与解包分用 四.IP地址IP VS Mac地址 五.So…...

Web开发:ORM框架之使用Freesql的导航属性

一、什么时候用导航属性 看数据库表的对应关系&#xff0c;一对多的时候用比较好&#xff0c;不用多写一个联表实体&#xff0c;而且查询高效 二、为实体配置导航属性 1.给关系是一的父表实体加上&#xff1a; [FreeSql.DataAnnotations.Navigate(nameof(子表.子表关联字段))]…...

NLP07-朴素贝叶斯问句分类之数据集加载(1/3)

一、概述 数据集加载&#xff08;Dataset Loading&#xff09;是机器学习、自然语言处理&#xff08;NLP&#xff09;等领域中的一个重要步骤&#xff0c;指的是将外部数据&#xff08;如文件、数据库、网络接口等&#xff09;加载到程序中&#xff0c;以便进行后续处理、分析…...

Rk3568驱动开发_点亮led灯(手动挡)_5

1.MMU简介 完成虚拟空间到物理空间的映射 内存保护设立存储器的访问权限&#xff0c;设置虚拟存储空间的缓冲特性 stm32点灯可以直接操作寄存器&#xff0c;但是linux点灯不能直接访问寄存器&#xff0c;linux会使能mmu linux中操作的都是虚拟地址&#xff0c;要想访问物理地…...

LangChain构建行业知识库实践:从架构设计到生产部署全指南

文章目录 引言:行业知识库的进化挑战一、系统架构设计1.1 核心组件拓扑1.2 模块化设计原则二、关键技术实现2.1 文档预处理流水线2.2 混合检索增强三、领域适配优化3.1 医学知识图谱融合3.2 检索结果重排序算法四、生产环境部署4.1 性能优化方案4.2 安全防护体系五、评估与调优…...

Vscode编辑器:解读文件结构、插件的导入导出、常用快捷键配置技巧及其常见问题的解决方案

一、文件与文件夹结构 1.文件结构 文件名作用.babelrc配置 Babel 编译选项&#xff0c;指定代码转译规则。.editorconfig定义项目代码格式规范&#xff0c;如缩进风格和空格数量等。.eslintignore列出 ESLint 忽略的文件或文件夹。.eslintrc.js配置 ESLint 的规则和插件。.gi…...

androidstudio 运行项目加载很慢,优化方法

一、Android Studio 运行项目加载缓慢可能由多种原因引起&#xff0c;以下是一些优化建议&#xff1a; 1. 升级硬件配置 内存&#xff1a;建议至少 8GB&#xff0c;16GB 或以上更佳。 SSD&#xff1a;使用 SSD 替代 HDD 以加快读写速度。 CPU&#xff1a;多核处理器有助于提…...

Vue性能翻倍秘籍

导读&#xff1a;某电商大促因工程化缺失导致页面崩溃&#xff01;本文通过双11级别流量压测&#xff0c;揭秘Vue项目性能优化的6大核心策略&#xff0c;涵盖构建提速、首屏优化、SSR实战等全链路方案。 工程化缺失引发的灾难现场 血泪案例&#xff1a; 某电商大促活动因工程化…...

线性回归 (Linear Regression)案例分析1

广告费用与产品销量 工欲善其事必先利其器数据分析1. 检查缺失值、异常值3. 散点图查看特征、响应相关性3. 热力图查看特征、响应相关性 特征工程1、导入必要工具包2、读取数据3、数据标准化4、保存特征工程的结果到文件&#xff0c;供机器学习模型使用 模型选择读取数据数据准…...

uni-app集成sqlite

Sqlite SQLite 是一种轻量级的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;广泛应用于各种应用程序中&#xff0c;特别是那些需要嵌入式数据库解决方案的场景。它不需要单独的服务器进程或系统配置&#xff0c;所有数据都存储在一个单一的普通磁盘文件中&am…...

策略模式环境类的实现方式对比

文章目录 1、策略模式2、聚合策略类实现方式一3、聚合策略类实现方式二4、对比5、补充&#xff1a;ApplicationContextAware接口 1、策略模式 近期工作中&#xff0c;需要处理4.x和5.x两个版本的数据&#xff0c;所以自然想到的是策略模式&#xff0c;写一个抽象类&#xff0c…...

Node.js 登录鉴权

目录 Session express-session 配置 express-session 函数 ts 要配置声明文件 express-session.d.ts express-session 使用 express-session 带角色 Token 什么是 JWT token jsonwebtoken 使用 jsonwebtoken 带角色 Session express 使用 express-session 管理会话&…...

【c++】【线程池】固定式线程池(FixedThreadPool)

【c】【线程池】固定式线程池&#xff08;FixedThreadPool&#xff09; 1属性 1.1 Task可调用对象 使用 function 包装器和using类型重命名 设置一个Task的可调用对象(可理解为函数指针) 这个Task也就是我们的任务 using Task std::function<void(void)>;定义了一个…...

高可用、高性能、负载均衡集群的区别

维度高可用集群高性能集群负载均衡集群核心目标服务持续可用&#xff0c;减少停机加速计算任务&#xff0c;提升处理能力请求分发算法、健康检查关键技术冗余、心跳检测、鼓掌转移并行计算、高速网络、分布式存储请求分发算法、健康检查典型应用数据库主从切换、关键业务系统科…...

Docker 与 Serverless(无服务器架构)

Serverless&#xff08;无服务器架构&#xff09; 是一种新的云计算架构&#xff0c;它通过让开发者专注于业务逻辑而无需管理服务器基础设施&#xff0c;来简化应用的开发和部署。Serverless 模型通常由云服务提供商管理基础设施的所有方面&#xff0c;而开发者只需提供代码和…...

mac 下 java 调用 gurobi 不能加载 jar

在 mac 电脑中的 java 始终不能加载 gurobi 的 jar 包&#xff0c;java 的开发软件 eclipse&#xff0c;idea 总是显示找不到 gurobi 的 jar 包&#xff0c;但是 jar 包明明就在那里。 摸索了三个小时&#xff0c;最后发现原因竟然是&#xff1a; jar 包太新&#xff0c;替换…...

halcon三维点云数据处理(二十七)remove_bin_for_3d_object_localization

目录 一、remove_bin_for_3d_object_localization代码第一部分二、remove_bin_for_3d_object_localization代码第二部分三、效果图一、remove_bin_for_3d_object_localization代码第一部分 1、读图构建3D模型。 2、一次二值化选取区域。 3、一次和背景差值选取区域。 4、在二维…...

Python 编程题 第二节:组合数字、乘法口诀表、水仙花数、反向输出四位数、判断三角形

组合数字 1-4不重复组成三位数&#xff0c;利用集合的去重 lst[] for i in range(1,5):for j in range(1,5):for m in range(1,5):s{i,j,m}if len(s)3:lst.append(i*100j*10m) print(lst) 乘法口诀表 修改换行符 for i in range(1,10):for j in range(1,i1):print(f"…...

【HTML— 快速入门】HTML 基础

准备工作 vscode下载 百度网盘 Subline Text 下载 Sublime Text下载 百度网盘 vscode 下载 Sublime Text 是一款轻量好用的文本编辑器&#xff0c;我们在写前端代码时&#xff0c;使用 Sublime Text 打开比使用记事本打开&#xff0c;得到的代码体验更好&#xff0c;比 vscode…...

【MATLAB中的图像数据结构】

MATLAB中的图像数据结构 目录 MATLAB中的图像数据结构目标 &#xff1a;知识点 &#xff1a;1. 图像的存储方式 &#xff1a;2. 图像的颜色空间 &#xff1a;3. 图像的像素操作 &#xff1a; 示例代码 &#xff1a;1. 读取和显示图像 &#xff1a;2. 查看图像信息 &#xff1a;…...

在线抽奖系统——项目介绍

目录 项目介绍 页面预览 需求分析 管理员登录注册 人员模块 奖品模块 活动模块 抽奖模块 系统设计 系统架构 项目环境 数据库设计 安全设计 完整代码&#xff1a;项目完整代码/在线抽奖系统/lottery-system Echo/project - 码云 - 开源中国 项目介绍 利用 MySQ…...

day7作业

编写一个如下场景&#xff1a; 有一个英雄Hero类&#xff0c;私有成员&#xff0c;攻击&#xff08;Atx&#xff09;&#xff0c;防御&#xff08;Defense&#xff09;&#xff0c;速度&#xff08;Speed)&#xff0c;生命值&#xff08;Blood)&#xff0c;以及所有的set get 方…...

JavaScript 系列之:Ajax、Promise、Axios

前言 同步&#xff1a;会阻塞。同步代码按照编写的顺序逐行依次执行&#xff0c;只有当前的任务完成后&#xff0c;才会执行下一个任务。 异步&#xff1a;异步代码不会阻塞后续代码的执行。当遇到异步操作时&#xff0c;JavaScript 会将该操作放入任务队列中&#xff0c;继续…...

AI人工智能机器学习之神经网络

1、概要 本篇学习AI人工智能机器学习之神经网络&#xff0c;以MLPClassifier和MLPRegressor为例&#xff0c;从代码层面讲述最常用的神经网络模型MLP。 2、神经网络 - 简介 在 Scikit-learn 中&#xff0c;神经网络是通过 sklearn.neural_network 模块提供的。最常用的神经网…...

鸿蒙开发深入浅出01(基本环境搭建、页面模板与TabBar)

鸿蒙开发深入浅出01&#xff08;基本环境搭建、页面模板与TabBar&#xff09; 1、效果展示2、下载 DevEco Studio3、创建项目4、新建页面模板5、更改应用信息6、新建以下页面7、Index.ets8、真机运行9、图片资源文件 1、效果展示 2、下载 DevEco Studio 访问官网根据自己的版本…...