C++ 六大常用设计模式详解(单例、工厂、策略、状态、观察者、代理)

设计模式分三大类:创建型 (对象怎么造)、行为型 (对象怎么交互)、结构型(对象怎么组合)。下面逐个讲原理、适用场景、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;
}

代理模式变种说明

  1. 虚拟代理:延迟创建重量级对象(上图示例)
  2. 保护代理:调用前校验权限,无权限禁止访问真实对象
  3. 日志代理:统一打印接口调用日志、耗时统计
  4. 远程代理:封装网络请求,隐藏跨进程 / 跨机器调用细节

优缺点

  • 优点:控制访问、扩展附加逻辑(缓存 / 鉴权 / 日志)、延迟加载、隔离真实对象
  • 缺点:多一层代理类,增加代码复杂度

模式快速分类总结

表格

模式 类型 核心作用 核心关键词
单例 创建型 全局唯一实例 私有构造、静态实例
工厂 创建型 统一创建对象,隔离 new 产品基类、工厂生产
策略 行为型 动态替换平行算法 Context 持有策略,外部切换
状态 行为型 根据内部状态自动切换逻辑 状态内部流转、状态机
观察者 行为型 一对多消息通知 发布 - 订阅、广播更新
代理 结构型 控制访问真实对象,附加逻辑 代理包装、前置后置处理

高频对比易混点

  1. 策略 vs 状态
    • 策略:算法平等互换,外部主动传入切换;无状态流转关系
    • 状态:对象自带状态,内部条件自动切换,有流转顺序
  2. 工厂 vs 代理
    • 工厂:只管创建对象;代理:包装已有对象,控制访问
  3. 单例 vs 静态类
    • 单例是对象,可继承、传参、延迟创建;静态类全静态,无实例生命周期
相关推荐
疯狂打码的少年1 小时前
【软件工程】结构化设计:模块独立性与耦合内聚
java·开发语言·笔记·软件工程
程高兴2 小时前
PMSM基于在线转动惯量辩识的滑模负载转矩观测器MATLAB-SIMULINK仿真模型
开发语言·matlab
kisloy2 小时前
【python零基础教程第24讲】代码规范与质量管控
开发语言·python
C++、Java和Python的菜鸟2 小时前
第4章 后端Web基础(基础知识)
java·开发语言
芷栀夏2 小时前
Java教育平台实战复盘:课程、考试与学习行为分析系统设计
java·开发语言·学习
从零开始的代码生活_2 小时前
C++ 多态详解:虚函数、动态绑定、抽象类与虚表原理
开发语言·c++·后端·学习·算法
xywww1682 小时前
AWS 账号权限怎么分:根用户和 IAM 用户区别及日常使用建议
大数据·开发语言·人工智能·python·gpt·云计算·aws
大彼方..3 小时前
C++ STL Vector 深度剖析:从内存管理到性能优化
开发语言·c++
炸薯条!3 小时前
从零开始学C++ (内存管理)
java·jvm·c++
cpp_25015 小时前
P6625 [省选联考 2020 B 卷] 卡牌游戏
数据结构·c++·算法·前缀和·贪心·洛谷题解·省选