C++ 设计模式:6 个常用模式的实战示例

1. 单例模式 Singleton

适用场景

  • 全局只需要一个对象
  • 例如:日志系统、配置管理器、数据库连接池管理器、设备句柄管理器

你会怎么想到它

如果你脑子里出现:

  • "全局唯一"
  • "整个程序都要共享同一份状态"
  • "不能重复创建,创建成本高"

大概率就会想到单例。

C++ 示例:日志管理器

cpp 复制代码
#include <iostream>
#include <mutex>
#include <string>

class Logger {
public:
    static Logger& instance() {
        static Logger inst; // C++11 起线程安全
        return inst;
    }

    void log(const std::string& msg) {
        std::cout << "[LOG] " << msg << std::endl;
    }

    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;

private:
    Logger() = default;
};

int main() {
    Logger::instance().log("Application started");
    return 0;
}

识别关键词

  • 全局唯一
  • 共享状态
  • 初始化一次
  • 统一入口

2. 工厂方法模式 Factory Method

适用场景

  • 你知道"要创建对象",但不想在业务代码里直接写 new 具体类
  • 让子类或工厂决定创建哪种对象
  • 例如:创建不同类型的图形、不同类型的通知方式、不同类型的文档解析器

你会怎么想到它

如果需求是:

  • "根据条件创建不同对象"
  • "对象类型未来可能扩展"
  • "调用方不关心具体类名"

那就很像工厂方法。

C++ 示例:创建不同通知对象

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>

FunWidgetFactory::FunWidgetFactory()
{
    //创建几个常用的
}

IFunWidget *FunWidgetFactory::getFunWidget(IFunWidget::WidgetType type)
{
    IFunWidget *pFunWidget = NULL;

    enum WidgetType{
        WGT_MAIN_MENU=0,        //主界面
        WGT_MEASURE,            //
        WGT_REVIEW,             //数据界面
        WGT_SETTING,            //设置界面
        WGT_SYS_CAL,            //质控界面
        WGT_SYS_INIT,           //开机初始化
        WGT_SHUTDOWN,           //关机界面

        WGT_INFO,               //设备信息
        WGT_TIME_DATE,          //时间日期
        WGT_SYSTEM_SET,         //系统设置
        WGT_REPORT_SET,         //
        WGT_PRINT_SET,          //
        WGT_COM_SET,            //
        WGT_TOUCH_CAL,          //
        WGT_DATA_MANAGE,        //
        WGT_Password,           //

        WGT_MAINTENANCE,        //
        WGT_LOCATING_SET,       //
        WGT_TEMP_SET,           //
        WGT_DA_SET,             //
        WGT_LED_SET,            //
        WGT_WIND_SW_TEST,       //
        WGT_ISN_SET,            //
        WGT_LED_ARG_SET,        //
        WGT_TEMP_ARG_SET,       //
        WGT_FAMHEX_CROSS_SET,   //

        WGT_OTHER_TEST_SET,     //
        WGT_SCREEN_TEST_SET,    //
        WGT_BUTUN_TEST_SET,     //
        WGT_AUTHORIZATION,     //
        WGT_AGENTMANAGE,         //
        WGT_SIGNAL_TEST,         //
        WGT_COOLING_CHECK,       //
        WGT_LED_TEST,           //
        WGT_LED_INIT,           //

        WidgetTypeMax
    };

    switch (type)
    {
        case IFunWidget::WGT_SYS_INIT:
        {
            qDebug() << "WGT_SYS_INIT";
            pFunWidget = SystemInitWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_MAIN_MENU:
        {
            qDebug() << "WGT_MAINMENU";
            pFunWidget = MainManu::GetInstance();
        }
        break;
        case IFunWidget::WGT_MEASURE:
        {
            qDebug() << "WGT_MEASURE";
            pFunWidget = MeasureWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_REVIEW:
        {
            qDebug() << "WGT_REVIEW";
            pFunWidget = ReviewWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_SETTING:
        {
            qDebug() << "WGT_SETTING";
            pFunWidget = SettingWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_INFO:
        {
            qDebug() << "WGT_INFO";
            pFunWidget = DeviceInfoWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_SHUTDOWN:
        {
            qDebug() << "WGT_SHUTDOWN";
            pFunWidget = ShutdownWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_TIME_DATE:
        {
            qDebug() << "WGT_DATE_SET";
            pFunWidget = DateSetWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_REPORT_SET:
        {
            qDebug() << "WGT_REPORT_SET";
            pFunWidget = ReportSetWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_COM_SET:
        {
            qDebug() << "WGT_COM_SET";
            pFunWidget = CommunicationSetWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_MAINTENANCE:
        {
            qDebug() << "WGT_MAINTENANCE";
            pFunWidget = MaintenanceWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_PRINT_SET:
        {
            qDebug() << "WGT_PRINT_SET";
            pFunWidget = PrintSettingWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_TOUCH_CAL:
        {
            qDebug() << "WGT_TOUCH_CALIBRATION";
            pFunWidget = TouchCalibrationWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_DATA_MANAGE:
        {
            qDebug() << "WGT_DATA_MANAGE";
            pFunWidget = DataManageWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_SYSTEM_SET:
        {
            qDebug() << "WGT_SYSTEM_SET";
            pFunWidget = SystemSetWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_Password:
        {
            qDebug() << "WGT_Password";
            pFunWidget = PasswordWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_LOCATING_SET:
        {
            qDebug() << "WGT_LOCATING_SET";
            pFunWidget = LocalSetWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_DA_SET:
        {
            qDebug() << "WGT_DA_SET";
            pFunWidget = DaSetWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_LED_SET:
        {
            qDebug() << "WGT_LED_SET";
            pFunWidget = LedSetWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_WIND_SW_TEST:
        {
            qDebug() << "WGT_WIND_SW_TEST";
            pFunWidget = WindTestWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_ISN_SET:
        {
            qDebug() << "WGT_ISN_SET";
            pFunWidget = ISNSetWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_TEMP_ARG_SET:
        {
            qDebug() << "WGT_TEMP_ARG_SET";
            pFunWidget = TempArgSetWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_OTHER_TEST_SET:
        {
            qDebug() << "WGT_OTHER_TEST_SET";
            pFunWidget = OtherTest::GetInstance();
        }
        break;
        case IFunWidget::WGT_SCREEN_TEST_SET:
        {
            qDebug() << "WGT_SCREEN_TEST_SET";
            pFunWidget = ScreenTestWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_BUTUN_TEST_SET:
        {
            qDebug() << "WGT_BUTUN_TEST_SET";
            pFunWidget = ButtunTest::GetInstance();
        }
        break;
        case IFunWidget::WGT_FAMHEX_CROSS_SET:
        {
            qDebug() << "WGT_FAMHEX_CROSS_SET";
            pFunWidget = FamHexCrossSet::GetInstance();
        }
        break;
        case IFunWidget::WGT_AUTHORIZATION:
        {
            qDebug() << "WGT_AUTHORIZATION";
            pFunWidget = AuthorizationWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_AGENTMANAGE:
        {
            qDebug() << "WGT_AGENTMANAGE";
            pFunWidget = AgentManageWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_SIGNAL_TEST:
        {
            qDebug() << "WGT_SIGNAL_TEST";
            pFunWidget = SignalTest::GetInstance();
        }
        break;
        case IFunWidget::WGT_COOLING_CHECK:
        {
            qDebug() << "WGT_COOLING_CHECK";
            pFunWidget = CoolingTempCheck::GetInstance();
        }
        break;
        case IFunWidget::WGT_LED_TEST:
        {
            qDebug() << "WGT_LED_TEST";
            pFunWidget = LedTestWidget::GetInstance();
        }
        break;
        case IFunWidget::WGT_LED_INIT:
        {
            qDebug() << "WGT_LED_INIT";
            pFunWidget = LedInitDetec::GetInstance();
        }
        break;
        default:
        {
            SHOW_DEBUG_INFO("default...");
        }
        break;
    }

    return pFunWidget;
}

int MainWindow()
{
    ...
    this->switchFunctionWidgetSlot(IFunWidget::WGT_MEASURE);
    ...
}

识别关键词

  • 创建对象
  • 隐藏 new
  • 根据类型分派
  • 扩展新产品

3. 观察者模式 Observer

适用场景

  • 一个对象状态变化时,需要自动通知多个依赖对象
  • 例如:消息订阅、GUI 事件、股票价格变化、传感器数据更新

你会怎么想到它

如果需求是:

  • "一变多通知"
  • "订阅/发布"
  • "事件驱动"
  • "监听某个变化"

那基本就是观察者。

C++ 示例:天气站通知多个显示器

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

class Observer {
public:
    virtual ~Observer() = default;
    virtual void update(float temperature) = 0;
};

class Subject {
public:
    void attach(Observer* obs) {
        observers.push_back(obs);
    }

    void detach(Observer* obs) {
        observers.erase(std::remove(observers.begin(), observers.end(), obs), observers.end());
    }

    void setTemperature(float temp) {
        temperature = temp;
        notify();
    }

protected:
    void notify() {
        for (auto* obs : observers) {
            obs->update(temperature);
        }
    }

private:
    std::vector<Observer*> observers;
    float temperature = 0.0f;
};

class PhoneDisplay : public Observer {
public:
    void update(float temperature) override {
        std::cout << "Phone display: " << temperature << " C" << std::endl;
    }
};

class WindowDisplay : public Observer {
public:
    void update(float temperature) override {
        std::cout << "Window display: " << temperature << " C" << std::endl;
    }
};

int main() {
    Subject weather;
    PhoneDisplay p;
    WindowDisplay w;

    weather.attach(&p);
    weather.attach(&w);

    weather.setTemperature(26.5f);
}

识别关键词

  • 订阅
  • 广播通知
  • 事件回调
  • 状态变化驱动多个对象更新

4. 策略模式 Strategy

适用场景

  • 同一件事有多种算法/处理方式,需要可替换
  • 例如:不同的排序算法、不同的支付方式、不同的压缩算法、不同的路径规划策略

你会怎么想到它

如果需求是:

  • "同样目标,不同算法"
  • "运行时可切换"
  • "避免 if-else 一堆判断"

那通常就是策略模式。

C++ 示例:支付策略

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>

class PayStrategy {
public:
    virtual ~PayStrategy() = default;
    virtual void pay(int amount) = 0;
};

class AlipayStrategy : public PayStrategy {
public:
    void pay(int amount) override {
        std::cout << "Pay " << amount << " by Alipay" << std::endl;
    }
};

class WechatPayStrategy : public PayStrategy {
public:
    void pay(int amount) override {
        std::cout << "Pay " << amount << " by WeChat Pay" << std::endl;
    }
};

class PaymentContext {
public:
    explicit PaymentContext(std::unique_ptr<PayStrategy> s)
        : strategy(std::move(s)) {}

    void checkout(int amount) {
        strategy->pay(amount);
    }

private:
    std::unique_ptr<PayStrategy> strategy;
};

int main() {
    PaymentContext c1(std::make_unique<AlipayStrategy>());
    c1.checkout(100);

    PaymentContext c2(std::make_unique<WechatPayStrategy>());
    c2.checkout(200);
}

识别关键词

  • 可替换算法
  • 同一接口,不同行为
  • 运行时切换
  • 消灭大分支判断

5. 代理模式 Proxy

适用场景

  • 你想通过一个"中间层"去控制真实对象
  • 可能是延迟加载、访问控制、缓存、日志、远程调用
  • 例如:图片懒加载代理、权限代理、远程服务代理

你会怎么想到它

如果需求是:

  • "先别直接访问真实对象"
  • "访问前后加点控制逻辑"
  • "真实对象太重,先代理一下"

那就是代理。

C++ 示例:图片懒加载

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>

class Image {
public:
    virtual ~Image() = default;
    virtual void display() = 0;
};

class RealImage : public Image {
public:
    explicit RealImage(const std::string& file) : filename(file) {
        loadFromDisk();
    }

    void display() override {
        std::cout << "Display " << filename << std::endl;
    }

private:
    void loadFromDisk() {
        std::cout << "Loading " << filename << " from disk..." << std::endl;
    }

    std::string filename;
};

class ImageProxy : public Image {
public:
    explicit ImageProxy(const std::string& file) : filename(file) {}

    void display() override {
        if (!realImage) {
            realImage = std::make_unique<RealImage>(filename);
        }
        realImage->display();
    }

private:
    std::string filename;
    std::unique_ptr<RealImage> realImage;
};

int main() {
    ImageProxy img("photo.png");
    std::cout << "Proxy created\n";
    img.display(); // 第一次才加载
    img.display(); // 直接显示
}

识别关键词

  • 中间层
  • 访问控制
  • 延迟加载
  • 缓存
  • 远程对象

6. 装饰器模式 Decorator

适用场景

  • 想在不修改原类的前提下,动态叠加功能
  • 例如:给文本增加加粗/颜色、给流增加缓冲/压缩/加密、给订单增加优惠券/运费计算

你会怎么想到它

如果需求是:

  • "在原功能基础上再加一层"
  • "功能可组合"
  • "不要用继承把类炸成很多组合"

那就很适合装饰器。

C++ 示例:咖啡加配料

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>

class Coffee {
public:
    virtual ~Coffee() = default;
    virtual std::string desc() const = 0;
    virtual int cost() const = 0;
};

class SimpleCoffee : public Coffee {
public:
    std::string desc() const override { return "Coffee"; }
    int cost() const override { return 10; }
};

class CoffeeDecorator : public Coffee {
public:
    explicit CoffeeDecorator(std::unique_ptr<Coffee> c)
        : coffee(std::move(c)) {}

protected:
    std::unique_ptr<Coffee> coffee;
};

class MilkDecorator : public CoffeeDecorator {
public:
    using CoffeeDecorator::CoffeeDecorator;

    std::string desc() const override {
        return coffee->desc() + " + Milk";
    }

    int cost() const override {
        return coffee->cost() + 3;
    }
};

class SugarDecorator : public CoffeeDecorator {
public:
    using CoffeeDecorator::CoffeeDecorator;

    std::string desc() const override {
        return coffee->desc() + " + Sugar";
    }

    int cost() const override {
        return coffee->cost() + 1;
    }
};

int main() {
    std::unique_ptr<Coffee> coffee = std::make_unique<SimpleCoffee>();
    coffee = std::make_unique<MilkDecorator>(std::move(coffee));
    coffee = std::make_unique<SugarDecorator>(std::move(coffee));

    std::cout << coffee->desc() << ", cost = " << coffee->cost() << std::endl;
}

识别关键词

  • 动态叠加功能
  • 包一层再加功能
  • 组合多个增强行为
  • 不想继承爆炸

快速记忆法:一句话区分

  • Singleton:一个类只能有一个实例
  • Factory Method:创建对象交给工厂
  • Observer:一个变,多个跟着变
  • Strategy:同一目标,不同算法可切换
  • Proxy:找对象前先过一层"代理"
  • Decorator:给对象"套外衣",功能层层叠加

你在项目里怎么快速判断

如果你看到这些需求,优先想到:

"全局唯一"

→ 单例

"创建哪种对象由条件决定"

→ 工厂方法

"一个对象状态变化要通知很多人"

→ 观察者

"同一个功能有多种实现,想动态切换"

→ 策略

"不直接访问真实对象,想加控制/懒加载"

→ 代理

"在不改原类的前提下叠加功能"

→ 装饰器


一个实际项目里的联想例子

假设你在做一个医疗设备软件:

  • 日志系统:单例
  • 根据设备型号创建不同采集器:工厂方法
  • 传感器数据变化通知 UI、告警模块、记录模块:观察者
  • 不同的报警阈值判定算法:策略
  • 远程设备接口调用的缓存/权限控制层:代理
  • 给数据流增加加密、压缩、校验:装饰器
相关推荐
qq_2949405510 小时前
Python环境搭建
开发语言·python
XMYX-011 小时前
40 - Go HTTP 客户端:从 http.Get 到高性能连接池
开发语言·http·golang
Daydream.V11 小时前
C++ 入门全攻略:从基础语法到核心特性
java·开发语言·c++
我是一颗柠檬11 小时前
【JDK8新特性】接口默认方法与静态方法Day8
java·开发语言·后端·intellij-idea
lulu121654407811 小时前
【开发者指南】Gemini 3.5开发入门:从API调用到Agent构建
java·开发语言·人工智能·python·ai编程
盲敲代码的阿豪11 小时前
Python 爬虫入门基础教程:从入门到实践
开发语言·爬虫·python
我能坚持多久11 小时前
STL详解——stack以及queue的模拟实现
开发语言·c++·学习
无限进步_11 小时前
【C++】智能指针的设计逻辑:RAII与资源安全
c++·算法·安全
会周易的程序员11 小时前
AI 编程助手:从“猫弄乱的线团”到“击鼓传花”的 Bug 修复
c++·人工智能·物联网·架构·bug·iot