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

    return 0;
}

总结

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用 Containerd 通过 HTTP 协议拉取 Harbor 私有镜像仓库的镜像

在 Kubernetes 1.24及以上版本环境中&#xff0c;docker不再被支持&#xff0c;主要使用Containerd 是常用的容器运行。默认情况下&#xff0c;Containerd 使用 HTTPS 协议与镜像仓库通信。然而&#xff0c;在某些场景下&#xff08;如测试环境或内部网络&#xff09;&#xff…

【论文笔记-TPAMI 2024】FreqFusion:用于密集图像预测的频率感知特征融合

Frequency-aware Feature Fusion for Dense Image Prediction 用于密集图像预测的频率感知特征融合 Abstract&#xff1a;密集图像预测任务要求具有强类别信息和高分辨率精确空间边界细节的特征。为了实现这一点&#xff0c;现代分层模型通常利用特征融合&#xff0c;直接添加…

PDF扫描档智能方向识别:多模型投票机制的实践测试 救活古典书籍

2025-02-22 20:10物联全栈123 尊敬的诸位&#xff01;我是一名物联网工程师。关注我&#xff0c;持续分享最新物联网与AI资讯和开发实战。期望与您携手探寻物联网与 AI 的无尽可能 RAG知识库搭建的过程中&#xff0c;扫描档pdf的支持和准确率一直是个大家都不愿主动提起的事情…

【deepseek】本地部署+webui访问

背景 最近deepseek很火&#xff0c;但是官网的老是被限流使用&#xff0c;还有就是自己也想着玩一玩&#xff0c;于是准备在自己电脑跑一个 直接附上结果地址mydeepseek 准备工作 windows和linux都可 我这里选择linux&#xff0c;ubuntu系统 安装ollama 看下图&#xff0…

【Vue工作原理】初始化启动文件加载流程

参考资料&#xff1a;配置参考 | Vue CLI vue-cli项目如果项目根目录下没有vue-config.js文件&#xff0c;默认入口文件entry&#xff0c;模板文件template&#xff0c;以及filename分别是什么?&#xff08;参考DeepSeek回答&#xff09; 根据Vue CLI文档&#xff0c;当没有配…

【构建工具】Gradle 8中Android BuildConfig的变化与开启方法

随着Gradle 8的发布&#xff0c;Android开发者需要注意一个重要变化&#xff1a;BuildConfig类的生成现在默认被关闭了&#xff01;&#xff01;&#xff01;。这个变化可能会影响许多依赖于BuildConfig的项目&#xff08;别问&#xff0c;问就是我也被影响了&#xff0c;多好用…

ESP32S3:参考官方提供的led_strip组件使用 SPI + DMA 方式驱动WS2812 RGB灯的实现思路 (实现各个平台移植使用该方式)

目录 引言使用SPI + DMA 方式实现思路分析1. 查看WS2812的datasheet手册2. 根据官方的led_strip组件的方式,自己手把手实现一遍3.完整的程序(实现霓虹灯效果)引言 参考官方提供的led_strip组件使用 SPI + DMA 方式驱动WS2812 RGB灯的实现思路,只有明白实现的思路,方能将其…

每日Attention学习24——Strip Convolution Block

模块出处 [TIP 21] [link] CoANet: Connectivity Attention Network for Road Extraction From Satellite Imagery 模块名称 Strip Convolution Block (SCB) 模块作用 多方向条形特征提取 模块结构 模块特点 类PSP设计&#xff0c;采用四个并行分支提取不同维度的信息相比于…

ctfshow——版本控制泄露源码

题目提示&#xff1a;版本控制很重要&#xff0c;但不要部署到生产环境更重要。 题目内容如下图所示 本题结合题目和提示可以知道&#xff0c;我们要通过查看生产环境来查找flag。 所以我们可以在URL上进行操作&#xff0c;这时候就需要目录扫描来查看了。 发现存在一个.git的…

关于网络端口探测:TCP端口和UDP端口探测区别

网络端口探测是网络安全领域中的一项基础技术&#xff0c;它用于识别目标主机上开放的端口以及运行在这些端口上的服务。这项技术对于网络管理和安全评估至关重要。在网络端口探测中&#xff0c;最常用的两种协议是TCP&#xff08;传输控制协议&#xff09;和UDP&#xff08;用…

某住宅小区地下车库安科瑞的新能源汽车充电桩的配电设计与应用方案 安科瑞 耿笠

摘要&#xff1a;纯电动商用车的工作环境存在路况复杂、工况恶劣等情况&#xff0c;导致整车电气设备的磨损速率加快&#xff0c;造成电气设备绝缘电阻持续下降&#xff0c;如不及时处理&#xff0c;可能存在安全隐患或引发重大安全事故。文章从绝缘故障检测原理出发&#xff0…

LeetCode详解之如何一步步优化到最佳解法:14. 最长公共前缀

LeetCode详解系列的总目录&#xff08;持续更新中&#xff09;&#xff1a;LeetCode详解之如何一步步优化到最佳解法&#xff1a;前100题目录&#xff08;更新中...&#xff09;-CSDN博客 LeetCode详解系列的上一题链接&#xff1a;LeetCode详解之如何一步步优化到最佳解法&am…

使用VS Code远程开发OpenAI API

由于OpenAI的API在国内不可用&#xff0c;我们要针对API进行开发困难比较大。 如果你有一个能使用OpenAI API的Linux服务器&#xff0c;我们可以方便地使用VS Code的远程开发功能来解决这个问题。 如果没有&#xff0c;你也可以试试获得一个免费的国外服务器&#xff0c;网上有…

代码审计入门学习

简介 HadSky轻论坛程序为个人原创PHP系统&#xff0c;作者为蒲乐天&#xff0c;后端基于puyuetianPHP框架驱动&#xff0c;前端基于 puyuetianUI框架驱动&#xff0c;默认编辑器为puyuetianEditor富文本编辑器&#xff0c;其他非原创框架及驱动JQuery.js 及Font-Awesome字体库…

Java线程池入门03

1. 这3种创建线程池的方式有风险 FixedThreadPool : 固定大小的线程池SingleThreadExecutor : 单个线程的线程池CachedThreadPool : 可缓存的线程池 FixedThreadPool内部其实也是使用ThreadPoolExecutor来创建的 等价于 : new ThreadPoolExecutor(nThreads, nThreads, 0L, Tim…

C#连接sql server

连接时&#xff0c;出现如下提示&#xff1a; ERROR [IM014] [Microsoft][ODBC 驱动程序管理器] 在指定的 DSN 中&#xff0c;驱动程序和应用程序之间的体系结构不匹配 原因是odbc的驱动和应用程序的架构不一致。我的odbc如下所示&#xff1a; 显示为64位&#xff0c;而c#程序显…

【实战 ES】实战 Elasticsearch:快速上手与深度实践-1.1.2典型应用场景:日志分析、实时搜索、推荐系统

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 为什么选择Elasticsearch&#xff1f;——典型应用场景深度解析1. 引言2. 日志分析&#xff1a;海量数据的实时洞察2.1 行业痛点2.2 ES解决方案关键技术实现&#xff1a; 2.…

SQLite 安装教程以及可视化工具介绍

目录 简述 1. Windows 系统安装 1.1 下载预编译的二进制文件 1.2 解压文件 1.3 配置环境变量 1.4 验证安装 2. GUI 可视化工具 2.1 免费工具 2.1.1 DB Browser for SQLite 2.1.2 SQLiteStudio 2.1.3 SQLite Expert 2.1.4 SQLiteGUI 2.1.5 Antares SQL 2.1.6 DbGa…

C#快速调用DeepSeek接口,winform接入DeepSeek查询资料 C#零门槛接入DeepSeek C#接入DeepSeek源代码下载

下载地址<------完整源码 在数字化转型加速的背景下&#xff0c;企业应用系统对智能服务的需求日益增长。DeepSeek作为先进的人工智能服务平台&#xff0c;其自然语言处理、图像识别等核心能力可显著提升业务系统的智能化水平。传统开发模式下&#xff0c;C#开发者需要耗费大…

IP------PPP协议

这只是IP的其中一块内容PPP&#xff0c;IP还有更多内容可以查看IP专栏&#xff0c;前一章内容为网络类型&#xff0c;可通过以下路径查看IP---网络类型-CSDN博客&#xff0c;欢迎指正 3.PPP协议 1.PPP优点 网络类型&#xff1a;p2p PPP---点到点协议 兼容性会更强凡是接口或…