设计模式分三大类:创建型 (对象怎么造)、行为型 (对象怎么交互)、结构型(对象怎么组合)。下面逐个讲原理、适用场景、C++ 完整可运行代码、优缺点。
一、单例模式(Singleton)------ 创建型
1. 核心思想
保证一个类全局只有唯一实例,提供全局访问点。
2. 使用场景
- 全局配置管理器、日志工具、数据库连接池、窗口管理器
- 资源昂贵,不能重复创建的对象
3. 两种实现:懒汉、饿汉
(1)饿汉单例(线程安全,程序启动直接创建)
#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 静态局部变量线程安全)
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. 简单工厂(静态工厂)
核心
一个工厂类,根据参数动态生产不同产品。
场景
同类产品多分支,创建逻辑集中管理。
#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. 工厂方法模式(优化版,符合开闭)
核心
一个产品对应一个工厂,基类定义工厂接口,新增产品只加工厂类,不改旧代码。
// 产品基类同上 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++ 代码示例:支付策略
#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. 示例:电梯状态机
#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++ 代码
#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. 静态代理完整示例(图片加载)
#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 静态类
- 单例是对象,可继承、传参、延迟创建;静态类全静态,无实例生命周期