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

C++四大设计模式:单例、工厂、观察者、策略

引言

在前面的文章中,我们学习了 C++ 语法、STL、数据结构。这些都是"怎么写代码"的工具。而设计模式解决的是更高层次的问题——"代码怎么组织才更好"。

设计模式是前辈们总结的、经过反复验证的代码组织方案。它不是凭空发明的,而是在无数项目中"踩坑"后提炼出的最佳实践。掌握设计模式,能让你写出更易维护、更易扩展、更易复用的代码。

本文聚焦 C++ 中最常用的四种设计模式:单例模式工厂模式观察者模式策略模式

第一部分:单例模式

一、什么是单例模式

保证一个类只有一个实例,并提供全局访问点。比如程序的配置管理器、日志系统、数据库连接池——这些东西整个程序只需要一份。

二、懒汉式(用到才创建)

#include <iostream> #include <mutex> using namespace std; class Singleton { private: static Singleton* instance; static mutex mtx; // 构造函数私有!外部不能 new Singleton() { cout << "单例创建" << endl; } // 禁止拷贝和赋值 Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; public: // 全局访问点(线程安全) static Singleton* getInstance() { if (instance == nullptr) { lock_guard<mutex> lock(mtx); // 加锁 if (instance == nullptr) { // 双重检查 instance = new Singleton(); } } return instance; } void doSomething() { cout << "工作" << endl; } }; // 静态成员初始化 Singleton* Singleton::instance = nullptr; mutex Singleton::mtx; int main() { Singleton* s1 = Singleton::getInstance(); Singleton* s2 = Singleton::getInstance(); cout << (s1 == s2) << endl; // 1(同一个对象) // Singleton s3; // 错误!构造私有 }

为什么用双重检查锁?

三、C++11 最简写法(推荐)

C++11 保证了静态局部变量的线程安全,一行搞定:

class Singleton { private: Singleton() = default; Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; public: static Singleton& getInstance() { static Singleton instance; // C++11 保证线程安全! return instance; } };

第二部分:工厂模式

一、简单工厂

把对象的创建逻辑集中到一个工厂类中,调用者不需要知道具体怎么创建。

#include <iostream> #include <string> using namespace std; // 产品基类 class Animal { public: virtual void speak() = 0; virtual ~Animal() = default; }; // 具体产品 class Dog : public Animal { public: void speak() override { cout << "汪汪" << endl; } }; class Cat : public Animal { public: void speak() override { cout << "喵喵" << endl; } }; // 简单工厂 class AnimalFactory { public: static Animal* createAnimal(const string& type) { if (type == "dog") return new Dog(); if (type == "cat") return new Cat(); return nullptr; } }; int main() { Animal* dog = AnimalFactory::createAnimal("dog"); dog->speak(); // 汪汪 Animal* cat = AnimalFactory::createAnimal("cat"); cat->speak(); // 喵喵 delete dog; delete cat; }

二、工厂方法模式

每个具体产品对应一个具体工厂,新增产品时不修改已有代码(开闭原则)。

// 抽象工厂 class AnimalFactory { public: virtual Animal* createAnimal() = 0; virtual ~AnimalFactory() = default; }; // 具体工厂 class DogFactory : public AnimalFactory { public: Animal* createAnimal() override { return new Dog(); } }; class CatFactory : public AnimalFactory { public: Animal* createAnimal() override { return new Cat(); } }; int main() { DogFactory dogFactory; Animal* dog = dogFactory.createAnimal(); dog->speak(); // 汪汪 CatFactory catFactory; Animal* cat = catFactory.createAnimal(); cat->speak(); // 喵喵 delete dog; delete cat; }
工厂类型特点适用场景
简单工厂一个工厂创建所有产品产品类型少,变化不频繁
工厂方法每个产品对应一个工厂产品类型多,经常新增

第三部分:观察者模式

定义一对多依赖关系,当被观察者状态变化时,自动通知所有观察者。比如 GUI 的事件监听、消息订阅通知。

#include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std; // 观察者接口 class Observer { public: virtual void update(const string& message) = 0; virtual ~Observer() = default; }; // 被观察者 class Subject { private: vector<Observer*> observers; string state; 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(state); } } // 改变状态并通知 void setState(const string& newState) { state = newState; notify(); // 状态一改变就通知 } }; // 具体观察者 class User : public Observer { private: string name; public: User(const string& name) : name(name) {} void update(const string& message) override { cout << name << " 收到通知:" << message << endl; } }; int main() { Subject subject; User alice("Alice"); User bob("Bob"); subject.attach(&alice); subject.attach(&bob); subject.setState("新版本发布了!"); // Alice 收到通知:新版本发布了! // Bob 收到通知:新版本发布了! subject.detach(&bob); subject.setState("服务器维护中..."); // Alice 收到通知:服务器维护中... // (Bob 已取消订阅,不会收到) }

第四部分:策略模式

定义一系列算法,把它们封装起来,让它们可以互相替换。比如排序可以选快排、归并;支付可以选微信、支付宝。

#include <iostream> #include <vector> #include <algorithm> using namespace std; // 策略接口 class SortStrategy { public: virtual void sort(vector<int>& data) = 0; virtual ~SortStrategy() = default; }; // 具体策略:升序 class AscendingSort : public SortStrategy { public: void sort(vector<int>& data) override { std::sort(data.begin(), data.end()); } }; // 具体策略:降序 class DescendingSort : public SortStrategy { public: void sort(vector<int>& data) override { std::sort(data.begin(), data.end(), greater<int>()); } }; // 使用策略的类 class DataProcessor { private: SortStrategy* strategy; public: void setStrategy(SortStrategy* s) { strategy = s; } void process(vector<int>& data) { if (strategy) { strategy->sort(data); } } }; int main() { vector<int> data = {5, 2, 8, 1, 9}; DataProcessor processor; AscendingSort asc; DescendingSort desc; // 用升序策略 processor.setStrategy(&asc); processor.process(data); // 1 2 5 8 9 // 切换到降序策略 processor.setStrategy(&desc); processor.process(data); // 9 8 5 2 1 }

策略模式的核心:用组合代替继承,算法可以在运行时灵活切换,不需要改代码。


总结

一、四种模式速查

模式核心思想关键实现
单例全局唯一实例构造私有 + 静态getInstance()
工厂把创建逻辑封装起来工厂类返回产品指针
观察者状态变化自动通知vector<Observer*>+notify()
策略算法可替换策略接口 +setStrategy()

二、一句话记忆

单例构造私有化保证全局唯一,工厂把创建和使用分离,观察者实现一对多自动通知,策略让算法可以随时替换——四大模式都是为了让代码更灵活、更好改、更好测。

http://www.rkmt.cn/news/1449963.html

相关文章:

  • 如何用Qwen-Image-Edit-Rapid-AIO实现4步闪电级AI图像编辑:新手终极指南
  • 告别手动输入!用Arduino IDE给ESP-01S烧录固件,实现一键连接阿里云(附固件源码)
  • 5个理由让你立即使用ModelViewer3D:Android上最轻量的3D模型查看神器 [特殊字符]
  • 告别Electron!用Go+Gio从零撸一个跨平台桌面小工具(附完整代码)
  • 解放双手,智能探索:《鸣潮》自动化助手全攻略
  • LabelImg图像标注工具终极指南:五分钟快速上手全攻略
  • 13.LeetCode 904. 水果成篮:从暴力枚举到滑动窗口的完美进阶
  • 大路灯护眼灯有必要吗?值得入手的护眼大路灯前十名推荐,不踩坑
  • 从Optional.orElse到Iterator.hasNext:写给Java新手的异常防御性编程手册
  • 告别盲目签约:2026年GEO优化服务商TOP5榜单 - GEO优化
  • 基于Arduino与DS18B20的温度监控报警系统设计与实现
  • 基于TSL2591与Arduino Nano的高精度DIY摄影测光表制作全攻略
  • Dify工作流完全指南:5分钟从零到一构建AI应用
  • PCB布线别再瞎画了!搞懂趋肤效应,你的高速信号质量能翻倍
  • 从‘Hello World’到数据流:用STM32CubeMX和HAL库玩转USART,实现与ESP8266的稳定通信
  • Arm Cortex-A715微架构异常解析与解决方案
  • Amass进阶玩法:除了`enum`,`intel`和`db`子命令在红队评估中怎么用?
  • 基于BD139晶体管与7812稳压的双通道LED闪烁灯设计与制作
  • 2026Q3 上海普陀家装甄选指南|老牌装企实测排行,从资质、报价、落地效果择优推荐 - 品牌优企推荐
  • Tessy工程迁移与复用实战:当.pdbx工程文件换了电脑或路径,如何快速恢复测试环境?
  • 自然语言控制电脑:UI-TARS-desktop如何重新定义人机交互范式
  • 别再手动量了!3DMAX里这个Smart Measure插件,5分钟搞定模型尺寸测量
  • Arduino与WS2812B打造儿童智能时钟:从硬件到软件的完整创客指南
  • Canvas-Editor协同编辑踩坑实录:从用户选区冲突到数据同步的那些‘坑’
  • 不只是主题美化:用Oh My Zsh插件打造你的命令行‘外挂’工作流(附zsh-autosuggestions高阶配置)
  • 基于Arduino的智能泡茶机DIY:从硬件选型到状态机编程全解析
  • 别再死记硬背了!用这5个钢琴/吉他实战片段,彻底搞懂乐理里的‘波音’怎么弹
  • CAD 2021新手必看:从安装到画第一张图的完整设置流程(含经典模式切换与关键选项解析)
  • 从一道综合题出发:实战绕过Canary+PIE+ASLR全保护(含Libc计算)
  • 从Modbus到Profinet:给S7-1200 PLC通讯协议选型画张“地图”(含RS485接线避坑)