设计模式分三大类:创建型(对象怎么造)、行为型(对象怎么交互)、结构型(对象怎么组合)。下面逐个讲原理、适用场景、C++ 完整可运行代码、优缺点。
一、单例模式(Singleton)—— 创建型
1. 核心思想
保证一个类全局只有唯一实例,提供全局访问点。
2. 使用场景
- 全局配置管理器、日志工具、数据库连接池、窗口管理器
- 资源昂贵,不能重复创建的对象
3. 两种实现:懒汉、饿汉
(1)饿汉单例(线程安全,程序启动直接创建)
cpp
#include <iostream> using namespace std; class Singleton { private: // 1. 私有构造,禁止外部new Singleton() { cout << "创建单例实例" << endl; } // 禁止拷贝、赋值 Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; // 2. 静态全局唯一实例(程序加载时初始化) static Singleton instance; public: // 3. 全局获取接口 static Singleton& getInstance() { return instance; } void log(string msg) { cout << "日志输出:" << msg << endl; } }; // 类外初始化静态实例 Singleton Singleton::instance; int main() { Singleton& s1 = Singleton::getInstance(); Singleton& s2 = Singleton::getInstance(); cout << &s1 << endl << &s2 << endl; // 地址完全相同 s1.log("测试单例"); return 0; }优点:天然线程安全,实现简单;缺点:程序启动就占用资源,不用也会创建。
(2)懒汉单例(用时才创建,C++11 静态局部变量线程安全)
cpp
class SingletonLazy { private: Singleton() = default; SingletonLazy(const SingletonLazy&) = delete; SingletonLazy& operator=(const SingletonLazy&) = delete; public: static SingletonLazy& getInstance() { // C++11规定:静态局部变量初始化线程安全 static SingletonLazy ins; return ins; } };优点:延迟加载,节省资源;推荐项目使用。
4. 优缺点
- 优点:全局唯一,统一管控资源,减少内存开销
- 缺点:违背单一职责、难以单元测试、生命周期依赖程序进程
二、工厂模式(Factory)—— 创建型(简单工厂 + 工厂方法)
分两层:简单工厂(静态工厂)、工厂方法模式
1. 简单工厂(静态工厂)
核心
一个工厂类,根据参数动态生产不同产品。
场景
同类产品多分支,创建逻辑集中管理。
cpp
#include <iostream> #include <string> using namespace std; // 产品基类 class Product { public: virtual void show() = 0; virtual ~Product() = default; }; // 产品A class ProductA : public Product { public: void show() override { cout << "产品A" << endl; } }; // 产品B class ProductB : public Product { public: void show() override { cout << "产品B" << endl; } }; // 简单工厂 class SimpleFactory { public: static Product* createProduct(string type) { if (type == "A") return new ProductA(); if (type == "B") return new ProductB(); return nullptr; } }; int main() { Product* p = SimpleFactory::createProduct("A"); p->show(); delete p; return 0; }缺点:新增产品必须修改工厂if-else,违反开闭原则。
2. 工厂方法模式(优化版,符合开闭)
核心
一个产品对应一个工厂,基类定义工厂接口,新增产品只加工厂类,不改旧代码。
cpp
// 产品基类同上 Product // 工厂基类 class Factory { public: virtual Product* create() = 0; virtual ~Factory() = default; }; // A工厂 class FactoryA : public Factory { public: Product* create() override { return new ProductA(); } }; // B工厂 class FactoryB : public Factory { public: Product* create() override { return new ProductB(); } }; int main() { Factory* f = new FactoryA(); Product* p = f->create(); p->show(); delete p; delete f; return 0; }适用:产品会持续扩展,需要严格遵守开闭原则。
工厂模式总结
- 作用:隔离对象创建逻辑,使用者只关心产品,不关心 new 细节
- 简单工厂:快速开发,产品少;工厂方法:易扩展,产品多
三、策略模式(Strategy)—— 行为型
1. 核心思想
把一系列可互换算法 / 业务逻辑封装成独立策略类,运行时动态切换,消除大量if/else。
2. 场景
- 支付方式(微信 / 支付宝 / 银行卡)、排序算法、折扣计算、文件解析器
3. C++ 代码示例:支付策略
cpp
#include <iostream> using namespace std; // 策略基类:支付算法 class PayStrategy { public: virtual void pay(int money) = 0; virtual ~PayStrategy() = default; }; // 微信支付策略 class WechatPay : public PayStrategy { public: void pay(int money) override { cout << "微信支付:" << money << "元" << endl; } }; // 支付宝策略 class AliPay : public PayStrategy { public: void pay(int money) override { cout << "支付宝支付:" << money << "元" << endl; } }; // 上下文Context:持有策略,对外统一接口 class Order { private: PayStrategy* strategy; public: // 动态设置策略 void setStrategy(PayStrategy* s) { strategy = s; } void checkout(int total) { strategy->pay(total); } }; int main() { Order order; PayStrategy* wechat = new WechatPay(); PayStrategy* ali = new AliPay(); order.setStrategy(wechat); order.checkout(100); // 运行时切换策略 order.setStrategy(ali); order.checkout(200); delete wechat; delete ali; return 0; }优缺点
- 优点:消灭臃肿 if-else,算法独立可单元测试,动态切换,符合开闭
- 缺点:策略类数量膨胀,客户端需要知道所有策略才能切换
四、状态模式(State)—— 行为型
1. 核心思想
对象的行为依赖自身状态,不同状态执行完全不同逻辑;把每个状态封装为独立类,状态切换自动流转。
和策略模式区分:策略:算法平行互换,外部主动切换;状态:状态内部自动流转,上下文随条件自动换状态。
2. 场景
电梯运行(开门 / 关门 / 上行 / 下行)、订单状态(待支付 / 已支付 / 已发货 / 完成)、游戏角色状态
3. 示例:电梯状态机
cpp
#include <iostream> using namespace std; // 前置声明上下文 class Elevator; // 状态基类 class State { protected: Elevator* ctx; public: State(Elevator* e) : ctx(e) {} virtual void open() = 0; virtual void close() = 0; virtual void run() = 0; virtual ~State() = default; }; // 上下文:电梯 class Elevator { public: State* curState; void setState(State* s) { curState = s; } void openDoor() { curState->open(); } void closeDoor() { curState->close(); } void runLift() { curState->run(); } }; // 开门状态 class OpenState : public State { public: using State::State; void open() override { cout << "门已经开着" << endl; } void close() override; void run() override { cout << "开门不能运行电梯" << endl; } }; // 关门状态 class CloseState : public State { public: using State::State; void open() override { cout << "开门" << endl; ctx->setState(new OpenState(ctx)); } void close() override { cout << "门已关闭" << endl; } void run() override { cout << "电梯启动运行" << endl; } }; void OpenState::close() { cout << "关门" << endl; ctx->setState(new CloseState(ctx)); } int main() { Elevator lift; lift.setState(new CloseState(&lift)); lift.openDoor(); // 切换开门状态 lift.runLift(); // 开门禁止运行 lift.closeDoor(); // 切回关门 lift.runLift(); return 0; }优缺点
- 优点:状态逻辑拆分,消除大量状态判断 if/switch,状态流转清晰
- 缺点:状态类数量多,状态切换管理复杂
五、观察者模式(Observer)—— 行为型,发布订阅
1. 核心思想
一对多依赖:主题(发布者)状态变化时,自动通知所有订阅观察者,解耦发布与接收。
2. 场景
GUI 事件监听、消息推送、日志订阅、游戏事件、MQ 简易实现
3. C++ 代码
cpp
#include <iostream> #include <vector> #include <string> using namespace std; // 观察者基类 class Observer { public: virtual void update(string msg) = 0; virtual ~Observer() = default; }; // 主题(发布者) class Subject { private: vector<Observer*> obsList; public: // 订阅 void attach(Observer* o) { obsList.push_back(o); } // 取消订阅 void detach(Observer* o) { for (auto it = obsList.begin(); it != obsList.end();) { if (*it == o) it = obsList.erase(it); else ++it; } } // 广播通知所有观察者 void notify(string msg) { for (auto o : obsList) o->update(msg); } }; // 具体观察者:用户A class UserA : public Observer { public: void update(string msg) override { cout << "用户A收到消息:" << msg << endl; } }; class UserB : public Observer { public: void update(string msg) override { cout << "用户B收到消息:" << msg << endl; } }; int main() { Subject news; UserA a; UserB b; news.attach(&a); news.attach(&b); news.notify("今日热点:C++设计模式"); // 全部收到 news.detach(&b); news.notify("第二条新闻"); // 只有A收到 return 0; }优缺点
- 优点:发布订阅完全解耦,一对多广播,动态增删观察者
- 缺点:通知顺序不可控,大量观察者会有性能开销;循环依赖易内存泄漏
六、代理模式(Proxy)—— 结构型
1. 核心思想
提供代理对象,控制对真实目标对象的访问;在调用真实对象前后加逻辑(缓存、鉴权、日志、延迟创建)。分类:静态代理、动态代理(C++ 无原生动态代理,一般用静态)
2. 使用场景
远程代理(RPC)、虚拟代理(大图片延迟加载)、保护代理(权限校验)、日志缓存代理
3. 静态代理完整示例(图片加载)
cpp
#include <iostream> #include <string> using namespace std; // 公共抽象接口 class Image { public: virtual void display() = 0; virtual ~Image() = default; }; // 真实对象:大图加载耗时 class RealImage : public Image { private: string path; public: RealImage(string p) : path(p) { cout << "加载大图资源:" << path << endl; } void display() override { cout << "展示图片:" << path << endl; } }; // 代理对象:虚拟代理,延迟加载 class ImageProxy : public Image { private: string path; RealImage* realImg = nullptr; public: ImageProxy(string p) : path(p) {} void display() override { // 延迟创建真实对象 if (!realImg) realImg = new RealImage(path); realImg->display(); } ~ImageProxy() { delete realImg; } }; int main() { // 创建代理,此时不加载大图 Image* img = new ImageProxy("big_pic.png"); cout << "页面渲染完成,点击才加载图片\n"; img->display(); // 第一次调用才加载 img->display(); // 第二次直接展示,无需重复加载 delete img; return 0; }代理模式变种说明
- 虚拟代理:延迟创建重量级对象(上图示例)
- 保护代理:调用前校验权限,无权限禁止访问真实对象
- 日志代理:统一打印接口调用日志、耗时统计
- 远程代理:封装网络请求,隐藏跨进程 / 跨机器调用细节
优缺点
- 优点:控制访问、扩展附加逻辑(缓存 / 鉴权 / 日志)、延迟加载、隔离真实对象
- 缺点:多一层代理类,增加代码复杂度
模式快速分类总结
表格
| 模式 | 类型 | 核心作用 | 核心关键词 |
|---|---|---|---|
| 单例 | 创建型 | 全局唯一实例 | 私有构造、静态实例 |
| 工厂 | 创建型 | 统一创建对象,隔离 new | 产品基类、工厂生产 |
| 策略 | 行为型 | 动态替换平行算法 | Context 持有策略,外部切换 |
| 状态 | 行为型 | 根据内部状态自动切换逻辑 | 状态内部流转、状态机 |
| 观察者 | 行为型 | 一对多消息通知 | 发布 - 订阅、广播更新 |
| 代理 | 结构型 | 控制访问真实对象,附加逻辑 | 代理包装、前置后置处理 |
高频对比易混点
- 策略 vs 状态
- 策略:算法平等互换,外部主动传入切换;无状态流转关系
- 状态:对象自带状态,内部条件自动切换,有流转顺序
- 工厂 vs 代理
- 工厂:只管创建对象;代理:包装已有对象,控制访问
- 单例 vs 静态类
- 单例是对象,可继承、传参、延迟创建;静态类全静态,无实例生命周期