C++常用设计模式

前言:C++代码设计模式总共有23种,分为创建型模式、结构型模式和行为模式。本文针对常用的单例模式、简单工厂模式、工厂方法模式和抽象工厂模式进行介绍。

目录

一、为什么需要设计模式

二、单例模式

三、简单工厂模式

四、工厂方法模式

五、抽象工厂模式


一、为什么需要设计模式

C++ 需要设计模式,核心是解决其面向对象编程(OOP)的痛点、适配底层开发场景,同时弥补语言原生特性的不足。

设计模式为 C++ 提供了 “标准化的解决方案”,让代码从 “随意写” 变成 “按规则写”,提升了C++代码的工程化能力。

二、单例模式

1)定义:保证一个类仅有一个实例,并对外提供一个全局访问点来访问这个实例

2)目的:解决 “对象重复创建” 问题,尤其适用于管理唯一的硬件资源(如 MCU 的时钟模块)

3)优缺点:优点是 省资源;全局访问,使用方便。缺点是 无法扩展(违背“开闭原则”(可参考SOLID软件设计原则 解析-ZEEKLOG博客));耦合度高;全局访问,大大增加了出错的概率。

4)C++示例

饿汉式单例:

饿汉式在程序启动时(静态变量初始化阶段)就创建实例,天生线程安全,但可能会造成资源浪费(如果实例从未被使用)。

#include <iostream> class SingletonHungry { private: // 私有构造函数:禁止外部创建对象 SingletonHungry() { std::cout << "饿汉式单例构造" << std::endl; } // 禁用拷贝构造和赋值运算符:防止实例被复制 SingletonHungry(const SingletonHungry&) = delete; SingletonHungry& operator=(const SingletonHungry&) = delete; // 静态成员变量:程序启动时初始化(全局区) static SingletonHungry instance; public: // 全局访问点:返回唯一实例 static SingletonHungry& getInstance() { return instance; } // 测试方法 void doSomething() { std::cout << "饿汉式单例执行操作" << std::endl; } }; // 静态成员变量初始化(类外定义) SingletonHungry SingletonHungry::instance; // 测试 int main() { // 获取实例并调用方法 SingletonHungry& s1 = SingletonHungry::getInstance(); SingletonHungry& s2 = SingletonHungry::getInstance(); // 验证是否是同一个实例(地址相同) std::cout << "s1 地址: " << &s1 << std::endl; std::cout << "s2 地址: " << &s2 << std::endl; s1.doSomething(); return 0; }

懒汉式单例:

懒汉式是按需初始化(第一次调用getInstance()时创建实例),C++11 及以上版本中,局部静态变量的初始化是线程安全的,这是最简洁且推荐的写法。

#include <iostream> class SingletonLazy { private: // 私有构造函数 SingletonLazy() { std::cout << "懒汉式单例构造" << std::endl; } // 禁用拷贝和赋值 SingletonLazy(const SingletonLazy&) = delete; SingletonLazy& operator=(const SingletonLazy&) = delete; public: // 全局访问点:局部静态变量(C++11 线程安全) static SingletonLazy& getInstance() { static SingletonLazy instance; // 第一次调用时初始化,仅初始化一次 return instance; } // 测试方法 void doSomething() { std::cout << "懒汉式单例执行操作" << std::endl; } // 析构函数(可选,用于验证析构时机) ~SingletonLazy() { std::cout << "懒汉式单例析构" << std::endl; } }; // 测试 int main() { // 第一次调用:创建实例 SingletonLazy& s1 = SingletonLazy::getInstance(); // 第二次调用:返回已创建的实例 SingletonLazy& s2 = SingletonLazy::getInstance(); std::cout << "s1 地址: " << &s1 << std::endl; std::cout << "s2 地址: " << &s2 << std::endl; s1.doSomething(); return 0; }

三、简单工厂模式

1)定义:一个工厂类根据传入的参数,动态创建不同的产品类实例(产品类需继承同一个抽象类 / 接口)。

2)目的:将 “对象创建逻辑” 和 “业务逻辑” 分离,避免在业务代码中直接new不同的产品对象。

3)优缺点:优点是 简化对象创建,产品创建与业务逻辑解耦。缺点是 工厂职责过重;如新增产品需修改代码,违背“开闭原则”(可参考SOLID软件设计原则 解析-ZEEKLOG博客)。

4)C++示例

#include <iostream> #include <string> #include <memory> // 抽象产品:图形 class Shape { public: virtual void draw() const = 0; virtual ~Shape() = default; }; // 具体产品:圆形/矩形 class Circle : public Shape { public: void draw() const override { std::cout << "绘制圆形" << std::endl; } }; class Rectangle : public Shape { public: void draw() const override { std::cout << "绘制矩形" << std::endl; } }; // 简单工厂:一个工厂创建所有产品 class ShapeFactory { public: static std::unique_ptr<Shape> createShape(const std::string& type) { if (type == "circle") return std::make_unique<Circle>(); if (type == "rectangle") return std::make_unique<Rectangle>(); return nullptr; } }; // 测试 int main_simple_factory() { auto circle = ShapeFactory::createShape("circle"); if (circle) circle->draw(); // 输出:绘制圆形 auto rect = ShapeFactory::createShape("rectangle"); if (rect) rect->draw(); // 输出:绘制矩形 return 0; }

四、工厂方法模式

1)定义:将 “产品创建” 延迟到具体工厂子类中,每个产品对应一个工厂子类,核心工厂类只定义创建产品的接口。

2)目的:解决简单工厂 “修改工厂代码” 的问题,新增产品只需新增工厂子类。

3)优缺点:优点是 符合 “开闭原则”,便于维护。缺点是 逻辑较复杂;类数量翻倍(产品+工厂),占用更多内存。

4)C++示例

#include <iostream> #include <memory> // 抽象产品:图形 class Shape { public: virtual void draw() const = 0; virtual ~Shape() = default; }; // 具体产品:圆形/矩形 class Circle : public Shape { public: void draw() const override { std::cout << "绘制圆形" << std::endl; } }; class Rectangle : public Shape { public: void draw() const override { std::cout << "绘制矩形" << std::endl; } }; // 抽象工厂:图形工厂 class ShapeFactory { public: virtual std::unique_ptr<Shape> createShape() const = 0; virtual ~ShapeFactory() = default; }; // 具体工厂:圆形工厂/矩形工厂 class CircleFactory : public ShapeFactory { public: std::unique_ptr<Shape> createShape() const override { return std::make_unique<Circle>(); } }; class RectangleFactory : public ShapeFactory { public: std::unique_ptr<Shape> createShape() const override { return std::make_unique<Rectangle>(); } }; // 测试 int main_factory_method() { std::unique_ptr<ShapeFactory> circleFactory = std::make_unique<CircleFactory>(); auto circle = circleFactory->createShape(); circle->draw(); // 输出:绘制圆形 std::unique_ptr<ShapeFactory> rectFactory = std::make_unique<RectangleFactory>(); auto rect = rectFactory->createShape(); rect->draw(); // 输出:绘制矩形 return 0; }

五、抽象工厂模式

1)定义:创建一系列相关 / 依赖“产品族”,而不指定具体类。

2)目的:解决 “产品族” 的创建问题,保证同一产品族的组件能兼容使用。

3)优缺点:优点是 产品族内组件兼容;扩展性强。缺点是 最复杂的工厂模式,类数量多,占用内存大。

4)C++示例

#include <iostream> #include <memory> // 抽象产品1:手机 class Phone { public: virtual void call() const = 0; virtual ~Phone() = default; }; // 具体产品1:小米手机/华为手机 class XiaomiPhone : public Phone { public: void call() const override { std::cout << "用小米手机打电话" << std::endl; } }; class HuaweiPhone : public Phone { public: void call() const override { std::cout << "用华为手机打电话" << std::endl; } }; // 抽象产品2:路由器 class Router { public: virtual void connect() const = 0; virtual ~Router() = default; }; // 具体产品2:小米路由器/华为路由器 class XiaomiRouter : public Router { public: void connect() const override { std::cout << "连接小米路由器" << std::endl; } }; class HuaweiRouter : public Router { public: void connect() const override { std::cout << "连接华为路由器" << std::endl; } }; // 抽象工厂:电子设备工厂(生产手机+路由器) class ElectronicFactory { public: virtual std::unique_ptr<Phone> createPhone() const = 0; virtual std::unique_ptr<Router> createRouter() const = 0; virtual ~ElectronicFactory() = default; }; // 具体工厂:小米工厂/华为工厂(生产对应品牌的产品族) class XiaomiFactory : public ElectronicFactory { public: std::unique_ptr<Phone> createPhone() const override { return std::make_unique<XiaomiPhone>(); } std::unique_ptr<Router> createRouter() const override { return std::make_unique<XiaomiRouter>(); } }; class HuaweiFactory : public ElectronicFactory { public: std::unique_ptr<Phone> createPhone() const override { return std::make_unique<HuaweiPhone>(); } std::unique_ptr<Router> createRouter() const override { return std::make_unique<HuaweiRouter>(); } }; // 测试 int main_abstract_factory() { // 小米工厂生产小米产品族 std::unique_ptr<ElectronicFactory> xiaomiFactory = std::make_unique<XiaomiFactory>(); auto xiaomiPhone = xiaomiFactory->createPhone(); auto xiaomiRouter = xiaomiFactory->createRouter(); xiaomiPhone->call(); // 输出:用小米手机打电话 xiaomiRouter->connect();// 输出:连接小米路由器 // 华为工厂生产华为产品族 std::unique_ptr<ElectronicFactory> huaweiFactory = std::make_unique<HuaweiFactory>(); auto huaweiPhone = huaweiFactory->createPhone(); auto huaweiRouter = huaweiFactory->createRouter(); huaweiPhone->call(); // 输出:用华为手机打电话 huaweiRouter->connect();// 输出:连接华为路由器 return 0; }

Read more

IoTDB Python原生接口全攻略:从基础读写到高级实战

IoTDB Python原生接口全攻略:从基础读写到高级实战

IoTDB Python原生接口全攻略:从基础读写到高级实战 做IoTDB时序数据开发的小伙伴,用Python对接肯定是高频需求,IoTDB官方的Python原生接口封装得特别友好,不管是基础的数据库连接、数据读写,还是高级的连接池管理、SSL加密、Pandas适配,全都能实现。今天就从环境搭建、基础使用,到DDL/DML操作、高级特性,再到测试和DBAPI适配,把IoTDB Python原生接口的用法一次性讲透,新手也能直接上手开发。 一、前期准备:安装依赖与包 用IoTDB Python原生接口前,得先装好两个核心依赖,一步到位不踩坑: 1. 安装thrift框架(要求版本≥0.13),是IoTDB底层的通信依赖 2. 安装IoTDB Python官方包(建议版本≥2.0),提供所有原生操作接口 直接用pip命令安装就行,执行以下两行: pip3 install thrift>=0.13 pip3

By Ne0inhk
【启发式算法】RRT算法详细介绍(Python)

【启发式算法】RRT算法详细介绍(Python)

📢本篇文章是博主人工智能(AI)领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在👉启发式算法专栏:        【启发式算法】(8)---《RRT算法详细介绍(Python)》 【启发式算法】RRT算法详细介绍(Python) 目录  一、RRT算法的核心思想  二、基本流程  三、RRT算法伪代码 [Python] RRT算法实现 [Results] 运行结果 [Notice]  注意事项 四、RRT的特点 五、改进版本:RRT* 六、应用场景         RRT(Rapidly-exploring Random Tree)快速扩展随机树是一种采样式路径规划算法,广泛应用于机器人运动规划、自动驾驶、无人机路径设计等领域。它特别适用于高维空间中的路径规划问题。下面是对RRT算法的详细介绍:  一、

By Ne0inhk
Python 属性描述符:从原理到 ORM 实践详解

Python 属性描述符:从原理到 ORM 实践详解

Python 属性描述符:从原理到 ORM 实践详解 * 一、为什么需要属性描述符?从property的局限性说起 * 二、属性描述符的定义与基础使用 * 2.1 什么是属性描述符? * 2.2 基础实现:整数类型校验描述符 * 2.3 在模型类中使用描述符 * 2.4 关键注意点:避免赋值死循环 * 三、属性描述符的分类:数据描述符与非数据描述符 * 3.1 数据描述符(Data Descriptor) * 3.2 非数据描述符(Non-data Descriptor) * 四、Python完整的属性查找过程:描述符的核心作用 * 4.1 核心查找顺序 * 4.2 关键验证:数据描述符覆盖实例属性 * 4.3 关键验证:

By Ne0inhk

Bug 算法路径规划实战:从数学建模到 Python 实现

1. 从“撞墙”到“绕行”:Bug算法的直觉理解 想象一下,你被蒙上眼睛,站在一个空旷的房间里,有人告诉你:“向前走十步,就能拿到桌子上的苹果。”你开始径直向前走。走了五步,你的膝盖“砰”地一声撞到了什么东西——是一把椅子。这时候你会怎么做?你肯定不会继续硬着头皮往前撞,而是会伸出手,摸着这把椅子的边缘,小心翼翼地绕着它走,直到你感觉前方没有阻碍了,再重新判断苹果的方向,继续前进。 这个“撞到就绕”的朴素策略,就是Bug算法最核心的思想。在机器人路径规划领域,Bug算法就是这样一种简单、直接、不需要“上帝视角”地图的局部规划方法。它不关心整个房间的布局,只关心“我”现在在哪里,“目标”在哪里,以及“我”眼前有没有障碍物。这种特性让它特别适合用在未知环境探索、实时避障以及计算资源有限的场景里,比如你家里的扫地机器人,或者在一个陌生仓库里穿梭的物流小车。 我刚开始接触路径规划时,

By Ne0inhk