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

news2025/2/27 16:07:28

工程实践中常见的几种设计模式解析及 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); // 15

    return 0;
}

总结

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2306959.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于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.使用

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…

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

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

uni-app集成sqlite

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

【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…

JavaScript 系列之:Ajax、Promise、Axios

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

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

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

FreeRTOS动态任务和静态任务创建

一.动态任务创建 1.搭建任务框架 去task.c中将任务参数复制到main中 然后将const去掉&#xff0c;它会限制参数类型&#xff0c;任务大小、任务优先级、任务句柄需要去宏定义&#xff0c;任务句柄是指针类型要取地址 vTaskStartScheduler(); //开启任务调度&#xff0c;.c…

QT:Graphics View的坐标系介绍

在 Qt 的 Graphics View 框架中&#xff0c;存在三种不同的坐标系&#xff0c;分别是 物品坐标系&#xff08;Item Coordinates&#xff09;、场景坐标系&#xff08;Scene Coordinates&#xff09; 和 视图坐标系&#xff08;View Coordinates&#xff09;。这三种坐标系在图形…

C# httpclient 和 Flurl.Http 的测试

关于C#调用接口或Post,Flurl封装了httpclient, CSDN有哥们提供了一个公网的测试网站&#xff0c;可以测试Post调用&#xff0c;我写了2个函数&#xff0c;测试httpclient和Flurl使用Post: async 和 await 是成对使用的&#xff0c;为了接受web异步返回的数据&#xff0c;winfor…

精选案例展 | 智己汽车—全栈可观测驱动智能化运营与成本优化

本案例为“观测先锋 2024 可观测平台创新应用案例大赛”精选案例&#xff0c;同时荣获IT168“2024技术卓越奖评选-年度创新解决方案”奖。 项目背景 近年来&#xff0c;中国汽车行业进入转型升级阶段&#xff0c;智能网联技术成为行业发展的核心。车联网、自动驾驶等技术的加速…