跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C++ 设计模式实战:观察者与策略模式深度解析

C++ 设计模式实战聚焦观察者与策略模式的核心实现与组合应用。文章通过气象站监控与电商折扣系统案例,详解同步/异步通知机制及线程安全优化,对比策略与工厂模式差异。结合智能物流调度系统展示两种模式联动方案,涵盖类结构、内存管理及并发处理技巧,帮助开发者构建高内聚低耦合的 C++ 业务逻辑。

flc发布于 2026/2/20更新于 2026/6/1318 浏览
C++ 设计模式实战:观察者与策略模式深度解析

C++ 设计模式实战:观察者与策略模式深度解析

本章学习目标与重点

  • 掌握观察者模式的核心设计思想、角色划分及 C++ 实现细节(同步/异步、线程安全)
  • 理解策略模式的设计原则、适用场景及与简单工厂模式的区别
  • 能够结合实际业务场景(如消息通知、算法切换)灵活运用两种模式
  • 解决模式应用中的关键问题(如观察者解注册、策略动态切换、循环依赖)

重点:观察者模式的事件分发机制、策略模式的算法封装逻辑、两种模式的组合使用技巧。

设计模式进阶认知:行为型模式的核心价值

在 C++ 开发中,行为型设计模式专注于解决'对象之间的交互方式'和'职责分配'问题。相比创建型模式(如工厂、单例)关注'对象创建',行为型模式更侧重'对象协作'。

为什么需要行为型设计模式?

实际开发中,我们常遇到以下交互相关的问题:

  • 一个对象状态变化时,需要通知多个其他对象,且通知对象的数量可能动态变化(如订单状态更新后,需通知库存、支付、物流系统);
  • 一个任务有多种实现算法,需根据场景动态切换(如排序算法可选择冒泡、快速、归并排序);
  • 交互逻辑分散在多个类中,导致代码耦合严重,难以维护和扩展;
  • 新增交互逻辑时,需修改现有代码,违反'开放 - 封闭原则'。

行为型模式通过标准化的交互规则,将'交互逻辑'与'业务逻辑'分离。例如观察者模式定义'通知 - 响应'规则,策略模式定义'算法封装 - 动态切换'规则,从而解决上述问题。

行为型模式的核心设计原则

行为型模式的设计始终围绕以下原则展开,这也是本章两种模式的核心指导思想:

  1. 封装变化:将易变的交互逻辑(如通知规则、算法实现)封装为独立的类,避免影响其他代码;
  2. 松耦合协作:交互的双方(如观察者与被观察者、策略使用者与策略实现)仅依赖抽象接口,不依赖具体实现;
  3. 职责单一:每个类只负责一项核心职责(如观察者只负责响应事件,策略类只负责实现算法);
  4. 开闭原则:新增交互逻辑(如新增观察者、新增策略)时,无需修改现有核心代码。

观察者模式:事件驱动的通知机制

观察者模式(Observer Pattern)又称发布 - 订阅模式(Publish-Subscribe Pattern),其核心思想是'定义对象间的一对多依赖关系,当一个对象状态发生变化时,所有依赖它的对象都会收到通知并自动更新'。

核心角色与交互流程

1. 核心角色
  • 被观察者(Subject):也称主题,维护一个观察者列表,提供注册、解注册观察者的接口,以及通知所有观察者的方法;
  • 观察者(Observer):定义接收通知的接口,当收到被观察者的通知时,执行相应的更新操作;
  • 具体被观察者(ConcreteSubject):被观察者的具体实现,维护自身状态,状态变化时触发通知;
  • 具体观察者(ConcreteObserver):观察者的具体实现,实现更新接口,响应被观察者的通知。
2. 交互流程
  1. 观察者通过被观察者的 RegisterObserver() 方法注册到被观察者中;
  2. 具体被观察者的状态发生变化;
  3. 具体被观察者调用 NotifyObservers() 方法,遍历所有注册的观察者;
  4. 被观察者调用每个观察者的 Update() 方法,传递状态变化信息;
  5. 观察者通过 Update() 方法接收信息并执行相应逻辑。

适用场景

  • 一个对象的状态变化需要触发多个其他对象的行为(如订单状态更新、股票价格变动);
  • 通知的接收者数量不固定,需要动态添加或移除(如系统中的消息订阅者);
  • 观察者与被观察者之间无需紧密耦合,希望通过抽象接口进行通信(如跨模块通知)。

基础实现:同步观察者模式(C++ 示例)

以'气象站数据监控系统'为例:气象站(被观察者)收集温度、湿度数据,当数据更新时,需通知显示屏、手机 App、报警器(观察者)进行相应展示或报警。

步骤 1:定义观察者抽象接口
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

// 观察者抽象接口
class Observer {
public:
    // 纯虚函数:接收通知并更新(参数:温度、湿度)
    virtual void Update(float temperature, float humidity) = 0;
    // 虚析构函数:确保子类析构时正确释放资源
    virtual ~Observer() {}
};
步骤 2:定义被观察者抽象接口
// 被观察者抽象接口
class Subject {
public:
    // 注册观察者
    virtual void RegisterObserver(Observer* observer) = 0;
    // 解注册观察者
    virtual void RemoveObserver(Observer* observer) = 0;
    // 通知所有观察者
    virtual void NotifyObservers() = 0;
    virtual ~Subject() {}
};
步骤 3:实现具体被观察者(气象站)
// 具体被观察者:气象站
class WeatherStation : public Subject {
private:
    vector<Observer*> observers; // 存储注册的观察者
    float temperature;           // 温度
    float humidity;              // 湿度

    // 检查观察者是否已注册(辅助函数)
    bool IsObserverRegistered(Observer* observer) const {
        return find(observers.begin(), observers.end(), observer) != observers.end();
    }

public:
    // 注册观察者:添加到列表(避免重复注册)
    void RegisterObserver(Observer* observer) override {
        if (observer == nullptr) {
            throw invalid_argument("观察者不能为空指针!");
        }
        if (!IsObserverRegistered(observer)) {
            observers.push_back(observer);
            cout << "观察者注册成功:" << typeid(*observer).name() << endl;
        } else {
            cout << "观察者已注册,无需重复添加:" << typeid(*observer).name() << endl;
        }
    }

    // 解注册观察者:从列表中移除
    void RemoveObserver(Observer* observer) override {
        auto iter = find(observers.begin(), observers.end(), observer);
        if (iter != observers.end()) {
            observers.erase(iter);
            cout << "观察者解注册成功:" << typeid(*observer).name() << endl;
        } else {
            cout << "观察者未注册,无法解注册:" << typeid(*observer).name() << endl;
        }
    }

    // 通知所有观察者:遍历列表并调用 Update 方法
    void NotifyObservers() override {
        cout << "\n气象站数据更新,开始通知所有观察者..." << endl;
        for (Observer* observer : observers) {
            observer->Update(temperature, humidity);
        }
    }

    // 模拟气象数据更新(外部调用,触发通知)
    void SetWeatherData(float temp, float humi) {
        this->temperature = temp;
        this->humidity = humi;
        cout << "\n气象站数据更新:温度=" << temp << "℃,湿度=" << humi << "%" << endl;
        NotifyObservers(); // 数据更新后自动通知
    }
};
步骤 4:实现具体观察者(显示屏、手机 App、报警器)
// 具体观察者 1:显示屏(展示实时数据)
class DisplayScreen : public Observer {
private:
    string screenName; // 显示屏名称(如"客厅显示屏")
public:
    DisplayScreen(const string& name) : screenName(name) {}
    void Update(float temperature, float humidity) override {
        cout << "[" << screenName << "] 实时数据展示:温度=" << temperature << "℃,湿度=" << humidity << "%" << endl;
    }
};

// 具体观察者 2:手机 App(推送通知)
class MobileApp : public Observer {
private:
    string userName; // 用户名
public:
    MobileApp(const string& name) : userName(name) {}
    void Update(float temperature, float humidity) override {
        cout << "[" << userName << "的手机 App] 推送通知:当前温度" << temperature << "℃,湿度" << humidity << "%" << endl;
    }
};

// 具体观察者 3:报警器(湿度超标时报警)
class Alarm : public Observer {
private:
    float humidityThreshold; // 湿度阈值(超过则报警)
public:
    Alarm(float threshold) : humidityThreshold(threshold) {}
    void Update(float temperature, float humidity) override {
        if (humidity > humidityThreshold) {
            cout << "[报警器] 警告!湿度超标(当前" << humidity << "%,阈值" << humidityThreshold << "%),请及时通风!" << endl;
        } else {
            cout << "[报警器] 湿度正常(当前" << humidity << "%),无报警" << endl;
        }
    }
};
步骤 5:客户端使用示例
int main() {
    try {
        // 1. 创建被观察者:气象站
        WeatherStation weatherStation;

        // 2. 创建观察者
        Observer* livingRoomScreen = new DisplayScreen("客厅显示屏");
        Observer* bedroomScreen = new DisplayScreen("卧室显示屏");
        Observer* userApp = new MobileApp("张三");
        Observer* humidityAlarm = new Alarm(60.0f); // 湿度阈值 60%

        // 3. 注册观察者
        weatherStation.RegisterObserver(livingRoomScreen);
        weatherStation.RegisterObserver(bedroomScreen);
        weatherStation.RegisterObserver(userApp);
        weatherStation.RegisterObserver(humidityAlarm);

        // 4. 模拟数据更新(触发第一次通知)
        weatherStation.SetWeatherData(25.5f, 55.0f);

        // 5. 解注册卧室显示屏(不再接收通知)
        weatherStation.RemoveObserver(bedroomScreen);
        cout << "\n--- 解注册卧室显示屏后 ---" << endl;

        // 6. 模拟数据更新(触发第二次通知,卧室显示屏不再接收)
        weatherStation.SetWeatherData(26.8f, 62.0f); // 湿度超标,报警器会报警

        // 7. 释放资源
        delete livingRoomScreen;
        delete bedroomScreen;
        delete userApp;
        delete humidityAlarm;
    } catch (const exception& e) {
        cout << "错误:" << e.what() << endl;
    }
    return 0;
}
运行结果
观察者注册成功:class DisplayScreen
观察者注册成功:class DisplayScreen
观察者注册成功:class MobileApp
观察者注册成功:class Alarm
气象站数据更新:温度=25.5℃,湿度=55.0%
气象站数据更新,开始通知所有观察者...
[客厅显示屏] 实时数据展示:温度=25.5℃,湿度=55.0%
[卧室显示屏] 实时数据展示:温度=25.5℃,湿度=55.0%
[张三的手机 App] 推送通知:当前温度 25.5℃,湿度 55.0%
[报警器] 湿度正常(当前 55.0%),无报警
观察者解注册成功:class DisplayScreen
--- 解注册卧室显示屏后 ---
气象站数据更新:温度=26.8℃,湿度=62.0%
气象站数据更新,开始通知所有观察者...
[客厅显示屏] 实时数据展示:温度=26.8℃,湿度=62.0%
[张三的手机 App] 推送通知:当前温度 26.8℃,湿度 62.0%
[报警器] 警告!湿度超标(当前 62.0%,阈值 60.0%),请及时通风!

进阶优化:线程安全与异步通知

基础实现是同步通知(被观察者在主线程中依次调用观察者的 Update() 方法),存在两个问题:

  1. 线程安全风险:若多个线程同时修改被观察者状态或注册/解注册观察者,可能导致列表遍历异常;
  2. 性能瓶颈:若某个观察者的 Update() 方法执行耗时较长,会阻塞其他观察者的通知。
优化方案 1:线程安全的同步通知(加锁保护)

使用 std::mutex 保护观察者列表的读写操作,确保多线程环境下的安全性:

#include <mutex>

// 线程安全的气象站(继承自原 WeatherStation,重写核心方法)
class ThreadSafeWeatherStation : public Subject {
private:
    vector<Observer*> observers;
    float temperature;
    float humidity;
    mutex mtx; // 互斥锁,保护观察者列表

public:
    void RegisterObserver(Observer* observer) override {
        if (observer == nullptr) {
            throw invalid_argument("观察者不能为空指针!");
        }
        lock_guard<mutex> lock(mtx); // 自动加锁/解锁
        auto iter = find(observers.begin(), observers.end(), observer);
        if (iter == observers.end()) {
            observers.push_back(observer);
            cout << "线程安全注册:" << typeid(*observer).name() << endl;
        }
    }

    void RemoveObserver(Observer* observer) override {
        lock_guard<mutex> lock(mtx);
        auto iter = find(observers.begin(), observers.end(), observer);
        if (iter != observers.end()) {
            observers.erase(iter);
            cout << "线程安全解注册:" << typeid(*observer).name() << endl;
        }
    }

    void NotifyObservers() override {
        lock_guard<mutex> lock(mtx);
        cout << "\n线程安全通知所有观察者..." << endl;
        // 拷贝一份观察者列表,避免遍历过程中列表被修改(如解注册)
        vector<Observer*> tempObservers = observers;
        lock.unlock(); // 提前解锁,减少阻塞时间
        for (Observer* observer : tempObservers) {
            observer->Update(temperature, humidity);
        }
    }

    void SetWeatherData(float temp, float humi) {
        lock_guard<mutex> lock(mtx);
        this->temperature = temp;
        this->humidity = humi;
        cout << "\n线程安全气象站数据:温度=" << temp << "℃,湿度=" << humi << "%" << endl;
        lock.unlock();
        NotifyObservers(); // 通知操作在解锁后执行,避免阻塞写操作
    }
};
优化方案 2:异步通知(使用线程池)

通过线程池异步执行观察者的 Update() 方法,避免单个观察者阻塞整个通知流程:

#include <thread>
#include <queue>
#include <condition_variable>

// 简单线程池(用于异步执行任务)
class ThreadPool {
private:
    vector<thread> workers;      // 工作线程
    queue<function<void()>> tasks; // 任务队列
    mutex mtx;                   // 保护任务队列
    condition_variable cv;       // 条件变量,唤醒线程
    bool stop;                   // 线程池停止标志

public:
    // 构造函数:创建 n 个工作线程
    ThreadPool(size_t n) : stop(false) {
        for (size_t i = 0; i < n; ++i) {
            workers.emplace_back([this]() {
                while (true) {
                    function<void()> task;
                    {
                        unique_lock<mutex> lock(this->mtx);
                        // 等待任务或停止信号
                        this->cv.wait(lock, [this]() {
                            return this->stop || !this->tasks.empty();
                        });
                        // 线程池停止且任务队列为空,退出线程
                        if (this->stop && this->tasks.empty()) {
                            return;
                        }
                        // 取出任务
                        task = move(this->tasks.front());
                        this->tasks.pop();
                    }
                    // 执行任务
                    task();
                }
            });
        }
    }

    // 析构函数:停止线程池
    ~ThreadPool() {
        {
            unique_lock<mutex> lock(mtx);
            stop = true;
        }
        cv.notify_all(); // 唤醒所有工作线程
        for (thread& worker : workers) {
            worker.join(); // 等待所有线程完成
        }
    }

    // 添加任务到线程池
    template<typename F>
    void Enqueue(F&& f) {
        {
            unique_lock<mutex> lock(mtx);
            if (stop) {
                throw runtime_error("线程池已停止,无法添加任务!");
            }
            tasks.emplace(forward<F>(f));
        }
        cv.notify_one(); // 唤醒一个工作线程
    }
};

// 异步通知的气象站
class AsyncWeatherStation : public Subject {
private:
    vector<Observer*> observers;
    float temperature;
    float humidity;
    mutex mtx;
    ThreadPool pool; // 线程池(2 个工作线程)

public:
    AsyncWeatherStation() : pool(2) {}

    void RegisterObserver(Observer* observer) override {
        lock_guard<mutex> lock(mtx);
        if (observer && find(observers.begin(), observers.end(), observer) == observers.end()) {
            observers.push_back(observer);
        }
    }

    void RemoveObserver(Observer* observer) override {
        lock_guard<mutex> lock(mtx);
        auto iter = find(observers.begin(), observers.end(), observer);
        if (iter != observers.end()) {
            observers.erase(iter);
        }
    }

    void NotifyObservers() override {
        lock_guard<mutex> lock(mtx);
        vector<Observer*> tempObservers = observers;
        float temp = temperature;
        float humi = humidity;
        // 异步执行每个观察者的 Update 方法
        for (Observer* observer : tempObservers) {
            pool.Enqueue([observer, temp, humi]() {
                observer->Update(temp, humi);
            });
        }
    }

    void SetWeatherData(float temp, float humi) {
        lock_guard<mutex> lock(mtx);
        this->temperature = temp;
        this->humidity = humi;
        cout << "\n异步气象站数据更新:温度=" << temp << "℃,湿度=" << humi << "%" << endl;
        lock.unlock();
        NotifyObservers();
    }
};
异步通知测试代码
// 模拟耗时的观察者(如网络请求)
class SlowObserver : public Observer {
public:
    void Update(float temperature, float humidity) override {
        cout << "[耗时观察者] 开始处理数据(模拟网络请求)..." << endl;
        this_thread::sleep_for(chrono::seconds(2)); // 模拟 2 秒耗时
        cout << "[耗时观察者] 数据处理完成:温度=" << temperature << "℃" << endl;
    }
};

int main() {
    AsyncWeatherStation weatherStation;
    Observer* fastObserver = new DisplayScreen("快速显示屏");
    Observer* slowObserver = new SlowObserver();
    weatherStation.RegisterObserver(fastObserver);
    weatherStation.RegisterObserver(slowObserver);
    weatherStation.SetWeatherData(24.0f, 58.0f);
    cout << "主线程继续执行其他任务..." << endl;
    // 等待异步任务完成(实际项目中无需手动等待,线程池会后台处理)
    this_thread::sleep_for(chrono::seconds(3));
    delete fastObserver;
    delete slowObserver;
    return 0;
}
异步通知运行结果
异步气象站数据更新:温度=24.0℃,湿度=58.0%
主线程继续执行其他任务...
[快速显示屏] 实时数据展示:温度=24.0℃,湿度=58.0%
[耗时观察者] 开始处理数据(模拟网络请求)...
[耗时观察者] 数据处理完成:温度=24.0℃

观察者模式的优缺点与避坑指南

优点
  • 解耦被观察者与观察者:两者仅依赖抽象接口,无需知道对方的具体实现;
  • 动态扩展:可随时添加/移除观察者,无需修改被观察者代码,符合'开放 - 封闭原则';
  • 广播通知:被观察者状态变化时,自动通知所有注册的观察者,无需手动调用。
缺点
  • 通知顺序不确定:同步通知时,观察者的更新顺序与注册顺序一致,但异步通知时顺序不可控;
  • 循环依赖风险:若观察者与被观察者相互引用,可能导致内存泄漏(需使用弱指针 weak_ptr 解决);
  • 性能开销:若观察者数量过多或 Update() 方法耗时,同步通知会导致性能瓶颈(需异步优化)。
避坑指南
  • 避免观察者列表遍历期间修改列表:注册/解注册时需加锁,或拷贝列表后遍历(如线程安全实现);
  • 处理观察者空指针:注册时校验观察者指针非空,避免通知时崩溃;
  • 内存管理:被观察者不负责销毁观察者,需由客户端统一管理,或使用智能指针(shared_ptr);
  • 避免过度通知:仅在状态真正变化时触发通知,避免无效更新(如气象站数据未变化时不通知)。

策略模式:算法的封装与动态切换

策略模式(Strategy Pattern)的核心思想是'定义一系列算法,将每个算法封装起来,并且使它们可以相互替换,让算法的变化独立于使用算法的客户'。

核心角色与设计逻辑

1. 核心角色
  • 策略抽象(Strategy):定义算法的抽象接口,所有具体策略都需实现该接口;
  • 具体策略(ConcreteStrategy):算法的具体实现,实现策略抽象接口;
  • 上下文(Context):使用策略的角色,持有一个策略对象的引用,提供切换策略的接口,负责调用策略执行算法。
2. 设计逻辑

将易变的算法(如排序算法、支付方式、压缩算法)封装为独立的策略类,上下文通过依赖注入或动态设置的方式使用策略,从而实现'算法切换无需修改上下文代码'。

适用场景

  • 一个任务有多种实现方式(算法),且需根据场景动态切换(如电商支付支持微信、支付宝、银行卡支付);
  • 算法细节复杂,且需要隐藏(如加密算法的实现细节不希望暴露给客户端);
  • 避免使用多重 if-else 或 switch 判断选择算法(如不同会员等级对应不同折扣策略);
  • 算法需要灵活扩展,新增算法时无需修改现有代码。

基础实现:电商折扣策略系统(C++ 示例)

以'电商平台折扣系统'为例:不同用户(普通用户、VIP 用户、超级 VIP 用户)对应不同折扣策略,且平台可能新增'节日折扣''优惠券折扣'等策略,使用策略模式可灵活扩展。

步骤 1:定义策略抽象接口(折扣算法)
#include <iostream>
#include <string>
#include <memory>

using namespace std;

// 策略抽象:折扣策略
class DiscountStrategy {
public:
    // 纯虚函数:计算折扣后的价格(参数:原价)
    virtual float CalculateDiscount(float originalPrice) const = 0;
    // 获取策略名称(用于日志输出)
    virtual string GetStrategyName() const = 0;
    virtual ~DiscountStrategy() {}
};
步骤 2:实现具体策略(不同折扣算法)
// 具体策略 1:普通用户策略(无折扣)
class NormalUserStrategy : public DiscountStrategy {
public:
    float CalculateDiscount(float originalPrice) const override {
        return originalPrice; // 无折扣,原价返回
    }
    string GetStrategyName() const override {
        return "普通用户无折扣";
    }
};

// 具体策略 2:VIP 用户策略(9 折)
class VIPUserStrategy : public DiscountStrategy {
public:
    float CalculateDiscount(float originalPrice) const override {
        return originalPrice * 0.9f; // 9 折
    }
    string GetStrategyName() const override {
        return "VIP 用户 9 折";
    }
};

// 具体策略 3:超级 VIP 用户策略(8 折 + 满 1000 减 200)
class SuperVIPUserStrategy : public DiscountStrategy {
public:
    float CalculateDiscount(float originalPrice) const override {
        float discountPrice = originalPrice * 0.8f; // 先打 8 折
        if (discountPrice >= 1000) {
            discountPrice -= 200; // 满 1000 减 200
        }
        return discountPrice;
    }
    string GetStrategyName() const override {
        return "超级 VIP 用户 8 折 + 满 1000 减 200";
    }
};

// 具体策略 4:节日折扣策略(7 折,限节日使用)
class FestivalDiscountStrategy : public DiscountStrategy {
public:
    float CalculateDiscount(float originalPrice) const override {
        return originalPrice * 0.7f; // 7 折
    }
    string GetStrategyName() const override {
        return "节日折扣 7 折";
    }
};
步骤 3:实现上下文(订单结算系统)
// 上下文:订单结算系统
class OrderSettlement {
private:
    // 持有策略对象(使用智能指针,自动管理内存)
    shared_ptr<DiscountStrategy> strategy;

public:
    // 构造函数:初始化策略(默认普通用户策略)
    OrderSettlement() : strategy(make_shared<NormalUserStrategy>()) {}

    // 动态切换策略(核心方法:支持运行时更换策略)
    void SetDiscountStrategy(shared_ptr<DiscountStrategy> newStrategy) {
        if (newStrategy == nullptr) {
            throw invalid_argument("策略不能为空!");
        }
        strategy = newStrategy;
        cout << "折扣策略切换为:" << strategy->GetStrategyName() << endl;
    }

    // 结算:调用当前策略计算最终价格
    float Settle(float originalPrice) const {
        if (originalPrice < 0) {
            throw invalid_argument("商品原价不能为负数!");
        }
        float finalPrice = strategy->CalculateDiscount(originalPrice);
        cout << "当前策略:" << strategy->GetStrategyName() << endl;
        cout << "商品原价:" << originalPrice << "元,最终价格:" << finalPrice << "元" << endl;
        return finalPrice;
    }
};
步骤 4:客户端使用示例
int main() {
    try {
        // 1. 创建上下文:订单结算系统
        OrderSettlement settlement;

        // 2. 普通用户结算(默认策略)
        cout << "=== 普通用户购买商品(原价 500 元)===" << endl;
        settlement.Settle(500.0f);

        // 3. 切换为 VIP 用户策略
        cout << "\n=== VIP 用户购买商品(原价 800 元)===" << endl;
        settlement.SetDiscountStrategy(make_shared<VIPUserStrategy>());
        settlement.Settle(800.0f);

        // 4. 切换为超级 VIP 用户策略
        cout << "\n=== 超级 VIP 用户购买商品(原价 1500 元)===" << endl;
        settlement.SetDiscountStrategy(make_shared<SuperVIPUserStrategy>());
        settlement.Settle(1500.0f);

        // 5. 切换为节日折扣策略
        cout << "\n=== 节日期间购买商品(原价 2000 元)===" << endl;
        settlement.SetDiscountStrategy(make_shared<FestivalDiscountStrategy>());
        settlement.Settle(2000.0f);

        // 6. 新增策略:无需修改结算系统代码,直接使用
        cout << "\n=== 新增优惠券策略(假设已实现)===" << endl;
        // 假设新增 CouponDiscountStrategy,直接通过 SetDiscountStrategy 切换
        // settlement.SetDiscountStrategy(make_shared<CouponDiscountStrategy>());
        // settlement.Settle(1000.0f);
    } catch (const exception& e) {
        cout << "结算失败:" << e.what() << endl;
    }
    return 0;
}
运行结果
=== 普通用户购买商品(原价 500 元)===
当前策略:普通用户无折扣
商品原价:500 元,最终价格:500 元
=== VIP 用户购买商品(原价 800 元)===
折扣策略切换为:VIP 用户 9 折
当前策略:VIP 用户 9 折
商品原价:800 元,最终价格:720 元
=== 超级 VIP 用户购买商品(原价 1500 元)===
折扣策略切换为:超级 VIP 用户 8 折 + 满 1000 减 200
当前策略:超级 VIP 用户 8 折 + 满 1000 减 200
商品原价:1500 元,最终价格:1000 元
=== 节日期间购买商品(原价 2000 元)===
折扣策略切换为:节日折扣 7 折
当前策略:节日折扣 7 折
商品原价:2000 元,最终价格:1400 元
=== 新增优惠券策略(假设已实现)===

策略模式与简单工厂模式的区别

很多开发者会混淆策略模式与简单工厂模式,两者的核心区别如下:

对比维度策略模式简单工厂模式
核心目的封装算法,支持动态切换封装对象创建,统一创建逻辑
关注点算法的'使用'与'切换'对象的'创建'
交互方式上下文持有策略对象,主动调用策略方法客户端调用工厂创建对象,自行使用
扩展性新增算法只需新增策略类,无侵入新增产品需修改工厂类(违反开闭原则)
适用场景算法多变、需动态切换产品类型少、创建逻辑简单

实战技巧:策略模式可与简单工厂模式结合使用!例如,在上下文内部通过简单工厂根据条件自动选择策略,无需客户端手动切换:

// 结合简单工厂的上下文
class FactoryStrategySettlement {
private:
    shared_ptr<DiscountStrategy> strategy;

    // 简单工厂:根据用户类型创建策略
    shared_ptr<DiscountStrategy> CreateStrategy(const string& userType) {
        if (userType == "normal") {
            return make_shared<NormalUserStrategy>();
        } else if (userType == "vip") {
            return make_shared<VIPUserStrategy>();
        } else if (userType == "super_vip") {
            return make_shared<SuperVIPUserStrategy>();
        } else {
            throw invalid_argument("不支持的用户类型:" + userType);
        }
    }

public:
    // 根据用户类型自动选择策略
    FactoryStrategySettlement(const string& userType) {
        strategy = CreateStrategy(userType);
    }

    float Settle(float originalPrice) const {
        float finalPrice = strategy->CalculateDiscount(originalPrice);
        cout << "用户类型对应策略:" << strategy->GetStrategyName() << endl;
        cout << "原价:" << originalPrice << "元,最终价:" << finalPrice << "元" << endl;
        return finalPrice;
    }
};

// 客户端使用
int main() {
    FactoryStrategySettlement vipSettlement("vip");
    vipSettlement.Settle(1000.0f); // 自动使用 VIP 策略
    return 0;
}

策略模式的优缺点与避坑指南

优点
  • 算法封装清晰:每个策略类只负责一种算法,职责单一,便于维护;
  • 支持动态切换:上下文可在运行时切换策略,无需重启程序;
  • 符合开闭原则:新增算法只需新增策略类,无需修改上下文或其他策略代码;
  • 避免多重条件判断:替代 if-else/switch,代码更简洁、易扩展。
缺点
  • 类数量增加:每新增一种算法,需新增一个策略类,若算法过多会导致类数量爆炸;
  • 客户端需了解策略:客户端需知道所有策略的存在,才能选择合适的策略(可通过工厂模式优化);
  • 策略间无依赖:若策略之间需要共享数据,需通过上下文传递,增加复杂度。
避坑指南
  • 策略粒度适中:避免将过于简单的算法封装为策略(如仅一行代码的计算),导致过度设计;
  • 使用智能指针管理策略:避免策略对象内存泄漏,简化客户端内存管理;
  • 策略不可变:设计策略类时,尽量使其为无状态类(不存储动态数据),确保线程安全;
  • 复杂策略组合:若需组合多种策略(如'折扣 + 优惠券'),可结合装饰者模式(后续章节讲解)。

实战案例:结合观察者模式与策略模式开发智能物流调度系统

需求分析

开发一个智能物流调度系统,核心需求如下:

  1. 订单状态变化时(如'已支付''已发货''已签收'),需通知客户 App、商家后台、物流系统;
  2. 调度算法可动态切换:根据订单类型(普通订单、加急订单、大件订单)选择不同的调度策略(如普通调度、优先调度、大件专用调度);
  3. 支持新增订单状态通知对象(如未来新增'保险公司'通知);
  4. 支持新增调度策略(如未来新增'冷链物流调度');
  5. 多线程环境下安全运行(如同时处理多个订单状态更新)。

设计思路

  • 观察者模式:处理订单状态通知,订单(被观察者)状态变化时,通知客户 App、商家后台等观察者;
  • 策略模式:处理调度算法,调度系统(上下文)根据订单类型选择对应的调度策略;
  • 组合设计:订单状态更新后,触发调度系统执行调度算法,调度结果通过观察者模式通知相关方。

完整实现代码

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <mutex>
#include <memory>
#include <thread>

using namespace std;

// -------------------------- 部分 1:观察者模式(订单状态通知) --------------------------
// 观察者抽象:接收订单状态通知
class OrderStatusObserver {
public:
    virtual void OnStatusChanged(const string& orderId, const string& status) = 0;
    virtual string GetObserverName() const = 0;
    virtual ~OrderStatusObserver() {}
};

// 具体观察者 1:客户 App
class CustomerAppObserver : public OrderStatusObserver {
public:
    void OnStatusChanged(const string& orderId, const string& status) override {
        cout << "[客户 App] 订单" << orderId << "状态更新为:" << status << ",已推送通知给客户" << endl;
    }
    string GetObserverName() const override { return "客户 App"; }
};

// 具体观察者 2:商家后台
class MerchantBackendObserver : public OrderStatusObserver {
public:
    void OnStatusChanged(const string& orderId, const string& status) override {
        cout << "[商家后台] 订单" << orderId << "状态更新为:" << status << ",已同步至商家管理系统" << endl;
    }
    string GetObserverName() const override { return "商家后台"; }
};

// 具体观察者 3:物流系统
class LogisticsSystemObserver : public OrderStatusObserver {
public:
    void OnStatusChanged(const string& orderId, const string& status) override {
        cout << "[物流系统] 订单" << orderId << "状态更新为:" << status << ",已触发物流调度" << endl;
    }
    string GetObserverName() const override { return "物流系统"; }
};

// 被观察者:订单
class Order : public Subject {
private:
    string orderId;
    string status; // 订单状态:"unpaid"(未支付)、"paid"(已支付)、"shipped"(已发货)、"received"(已签收)
    vector<OrderStatusObserver*> observers;
    mutex mtx;

public:
    Order(const string& id) : orderId(id), status("unpaid") {}

    // 注册观察者(重写 Subject 接口)
    void RegisterObserver(Observer* observer) override {
        if (observer == nullptr) return;
        OrderStatusObserver* statusObserver = dynamic_cast<OrderStatusObserver*>(observer);
        if (statusObserver == nullptr) {
            throw invalid_argument("观察者类型不匹配!");
        }
        lock_guard<mutex> lock(mtx);
        auto iter = find(observers.begin(), observers.end(), statusObserver);
        if (iter == observers.end()) {
            observers.push_back(statusObserver);
            cout << "订单" << orderId << "注册观察者:" << statusObserver->GetObserverName() << endl;
        }
    }

    // 解注册观察者(重写 Subject 接口)
    void RemoveObserver(Observer* observer) override {
        OrderStatusObserver* statusObserver = dynamic_cast<OrderStatusObserver*>(observer);
        if (statusObserver == nullptr) return;
        lock_guard<mutex> lock(mtx);
        auto iter = find(observers.begin(), observers.end(), statusObserver);
        if (iter != observers.end()) {
            observers.erase(iter);
            cout << "订单" << orderId << "解注册观察者:" << statusObserver->GetObserverName() << endl;
        }
    }

    // 通知观察者(重写 Subject 接口)
    void NotifyObservers() override {
        lock_guard<mutex> lock(mtx);
        vector<OrderStatusObserver*> tempObservers = observers;
        string tempOrderId = orderId;
        string tempStatus = status;
        // 异步通知(避免阻塞订单状态更新)
        thread([tempObservers, tempOrderId, tempStatus]() {
            for (OrderStatusObserver* observer : tempObservers) {
                observer->OnStatusChanged(tempOrderId, tempStatus);
            }
        }).detach();
    }

    // 更新订单状态(触发通知)
    void UpdateStatus(const string& newStatus) {
        if (newStatus != "unpaid" && newStatus != "paid" && newStatus != "shipped" && newStatus != "received") {
            throw invalid_argument("无效的订单状态:" + newStatus);
        }
        lock_guard<mutex> lock(mtx);
        if (this->status == newStatus) {
            cout << "订单" << orderId << "状态未变化(当前:" << newStatus << ")" << endl;
            return;
        }
        this->status = newStatus;
        cout << "\n订单" << orderId << "状态更新为:" << newStatus << endl;
        NotifyObservers();
    }

    // 获取订单状态
    string GetStatus() const {
        lock_guard<mutex> lock(mtx);
        return status;
    }

    // 获取订单 ID
    string GetOrderId() const { return orderId; }
};

// -------------------------- 部分 2:策略模式(物流调度算法) --------------------------
// 策略抽象:调度策略
class DispatchStrategy {
public:
    virtual string Dispatch(const string& orderId, const string& orderType) const = 0;
    virtual string GetStrategyName() const = 0;
    virtual ~DispatchStrategy() {}
};

// 具体策略 1:普通调度(适用于普通订单)
class NormalDispatchStrategy : public DispatchStrategy {
public:
    string Dispatch(const string& orderId, const string& orderType) const override {
        string result = "订单" + orderId + "(" + orderType + ")使用普通调度:分配常规物流车辆,预计 3-5 天送达";
        cout << result << endl;
        return result;
    }
    string GetStrategyName() const override { return "普通调度策略"; }
};

// 具体策略 2:优先调度(适用于加急订单)
class PriorityDispatchStrategy : public DispatchStrategy {
public:
    string Dispatch(const string& orderId, const string& orderType) const override {
        string result = "订单" + orderId + "(" + orderType + ")使用优先调度:分配加急物流车辆,预计 1-2 天送达";
        cout << result << endl;
        return result;
    }
    string GetStrategyName() const override { return "优先调度策略"; }
};

// 具体策略 3:大件调度(适用于大件订单)
class LargeItemDispatchStrategy : public DispatchStrategy {
public:
    string Dispatch(const string& orderId, const string& orderType) const override {
        string result = "订单" + orderId + "(" + orderType + ")使用大件调度:分配专用大件物流车辆,预计 2-4 天送达";
        cout << result << endl;
        return result;
    }
    string GetStrategyName() const override { return "大件调度策略"; }
};

// 上下文:物流调度系统
class LogisticsDispatchSystem {
private:
    mutex mtx; // 策略映射:订单类型 -> 策略(支持动态配置)
    map<string, shared_ptr<DispatchStrategy>> strategyMap;

public:
    // 初始化默认策略
    LogisticsDispatchSystem() {
        strategyMap["normal"] = make_shared<NormalDispatchStrategy>();   // 普通订单
        strategyMap["express"] = make_shared<PriorityDispatchStrategy>(); // 加急订单
        strategyMap["large"] = make_shared<LargeItemDispatchStrategy>();  // 大件订单
    }

    // 注册新策略(支持动态新增)
    void RegisterStrategy(const string& orderType, shared_ptr<DispatchStrategy> strategy) {
        if (orderType.empty() || strategy == nullptr) {
            throw invalid_argument("订单类型或策略不能为空!");
        }
        lock_guard<mutex> lock(mtx);
        strategyMap[orderType] = strategy;
        cout << "注册新调度策略:订单类型=" << orderType << ",策略=" << strategy->GetStrategyName() << endl;
    }

    // 执行调度(根据订单类型选择策略)
    string DispatchOrder(const string& orderId, const string& orderType) {
        lock_guard<mutex> lock(mtx);
        auto iter = strategyMap.find(orderType);
        if (iter == strategyMap.end()) {
            throw invalid_argument("不支持的订单类型:" + orderType);
        }
        return iter->second->Dispatch(orderId, orderType);
    }
};

// -------------------------- 部分 3:系统整合与客户端测试 --------------------------
// 系统整合:订单状态更新后触发调度
void OnOrderStatusUpdated(const shared_ptr<Order>& order, const shared_ptr<LogisticsDispatchSystem>& dispatchSystem, const string& orderType) {
    string status = order->GetStatus();
    if (status == "paid") {
        // 订单已支付,触发调度
        cout << "\n--- 订单" << order->GetOrderId() << "已支付,开始物流调度 ---" << endl;
        dispatchSystem->DispatchOrder(order->GetOrderId(), orderType);
    }
}

int main() {
    try {
        // 1. 创建物流调度系统
        auto dispatchSystem = make_shared<LogisticsDispatchSystem>();

        // 2. 创建观察者
        auto customerApp = make_shared<CustomerAppObserver>();
        auto merchantBackend = make_shared<MerchantBackendObserver>();
        auto logisticsSystem = make_shared<LogisticsSystemObserver>();

        // 3. 创建订单(普通订单、加急订单)
        auto normalOrder = make_shared<Order>("ORD20240501001"); // 普通订单
        auto expressOrder = make_shared<Order>("ORD20240501002"); // 加急订单

        // 4. 为订单注册观察者
        normalOrder->RegisterObserver(customerApp.get());
        normalOrder->RegisterObserver(merchantBackend.get());
        normalOrder->RegisterObserver(logisticsSystem.get());
        expressOrder->RegisterObserver(customerApp.get());
        expressOrder->RegisterObserver(merchantBackend.get());
        expressOrder->RegisterObserver(logisticsSystem.get());

        // 5. 模拟普通订单流程:未支付 -> 已支付(触发调度)-> 已发货 -> 已签收
        cout << "=== 普通订单流程 ===" << endl;
        normalOrder->UpdateStatus("paid"); // 已支付,触发调度
        this_thread::sleep_for(chrono::seconds(1)); // 等待异步通知完成
        OnOrderStatusUpdated(normalOrder, dispatchSystem, "normal");
        normalOrder->UpdateStatus("shipped"); // 已发货
        this_thread::sleep_for(chrono::seconds(1));
        normalOrder->UpdateStatus("received"); // 已签收
        this_thread::sleep_for(chrono::seconds(1));

        // 6. 模拟加急订单流程
        cout << "\n=== 加急订单流程 ===" << endl;
        expressOrder->UpdateStatus("paid"); // 已支付,触发调度
        this_thread::sleep_for(chrono::seconds(1));
        OnOrderStatusUpdated(expressOrder, dispatchSystem, "express");

        // 7. 新增冷链物流策略(扩展功能)
        class ColdChainDispatchStrategy : public DispatchStrategy {
        public:
            string Dispatch(const string& orderId, const string& orderType) const override {
                return "订单" + orderId + "(" + orderType + ")使用冷链调度:分配冷藏物流车辆,预计 1-2 天送达";
            }
            string GetStrategyName() const override { return "冷链调度策略"; }
        };
        dispatchSystem->RegisterStrategy("cold_chain", make_shared<ColdChainDispatchStrategy>());

        // 8. 测试新增的冷链订单
        auto coldChainOrder = make_shared<Order>("ORD20240501003");
        coldChainOrder->RegisterObserver(customerApp.get());
        cout << "\n=== 冷链订单流程 ===" << endl;
        coldChainOrder->UpdateStatus("paid");
        this_thread::sleep_for(chrono::seconds(1));
        OnOrderStatusUpdated(coldChainOrder, dispatchSystem, "cold_chain");
    } catch (const exception& e) {
        cout << "系统错误:" << e.what() << endl;
    }
    return 0;
}

代码说明与运行效果

核心设计亮点
  • 观察者模式负责'状态通知':订单状态变化时,异步通知客户 App、商家后台等,解耦订单与通知接收方;
  • 策略模式负责'算法调度':根据订单类型动态选择调度策略,支持新增策略(如冷链调度)无侵入扩展;
  • 组合使用:订单'已支付'状态触发物流调度,实现两种模式的联动,满足复杂业务流程;
  • 线程安全:观察者注册/解注册、订单状态更新、策略调度均加锁保护,支持多线程并发处理。
运行结果(关键片段)
订单 ORD20240501001 注册观察者:客户 App
订单 ORD20240501001 注册观察者:商家后台
订单 ORD20240501001 注册观察者:物流系统
...
=== 普通订单流程 ===
订单 ORD20240501001 状态更新为:paid
[客户 App] 订单 ORD20240501001 状态更新为:paid,已推送通知给客户
[商家后台] 订单 ORD20240501001 状态更新为:paid,已同步至商家管理系统
[物流系统] 订单 ORD20240501001 状态更新为:paid,已触发物流调度
--- 订单 ORD20240501001 已支付,开始物流调度 ---
订单 ORD20240501001(normal)使用普通调度:分配常规物流车辆,预计 3-5 天送达
...
=== 冷链订单流程 ===
注册新调度策略:订单类型=cold_chain,策略=冷链调度策略
订单 ORD20240501003 状态更新为:paid
[客户 App] 订单 ORD20240501003 状态更新为:paid,已推送通知给客户
--- 订单 ORD20240501003 已支付,开始物流调度 ---
订单 ORD20240501003(cold_chain)使用冷链调度:分配冷藏物流车辆,预计 1-2 天送达

本章总结

本章重点讲解了 C++ 开发中常用的两种行为型设计模式:观察者模式和策略模式,核心要点总结如下:

  1. 观察者模式:
    • 核心价值:实现'一对多'的通知机制,解耦被观察者与观察者;
    • 关键实现:抽象观察者接口、被观察者维护观察者列表、通知机制(同步/异步);
    • 进阶优化:线程安全(加锁)、异步通知(线程池)、避免循环依赖(弱指针);
    • 适用场景:状态变化通知、消息订阅、跨模块通信。
  2. 策略模式:
    • 核心价值:封装算法,支持动态切换,替代多重条件判断;
    • 关键实现:策略抽象接口、具体策略类、上下文持有并调用策略;
    • 与工厂模式区别:策略模式关注'算法使用与切换',工厂模式关注'对象创建';
    • 适用场景:算法多变、动态切换逻辑(如支付方式、调度算法、折扣策略)。
  3. 模式组合技巧:
    • 观察者模式 + 策略模式:状态变化触发策略执行(如订单支付后触发对应调度策略);
    • 策略模式 + 简单工厂:上下文自动选择策略,简化客户端使用;
    • 观察者模式 + 线程池:异步通知提升系统性能,避免阻塞。
  4. 实战注意事项:
    • 避免过度设计:简单场景(如固定几个观察者/策略)可简化实现,无需严格遵循模式结构;
    • 线程安全优先:多线程环境下,需保护共享资源(如观察者列表、策略映射);
    • 内存管理:使用智能指针(shared_ptr/weak_ptr)避免内存泄漏;
    • 符合开闭原则:新增功能时,优先通过扩展类实现,而非修改现有代码。

通过本章学习,你应能熟练运用观察者模式和策略模式解决实际开发中的'交互通知'和'算法切换'问题,结合两种模式的组合使用,编写高内聚、低耦合、易扩展的 C++ 代码。后续章节将继续讲解其他行为型设计模式(如装饰者模式、适配器模式),进一步提升你的代码设计能力。

目录

  1. C++ 设计模式实战:观察者与策略模式深度解析
  2. 本章学习目标与重点
  3. 设计模式进阶认知:行为型模式的核心价值
  4. 为什么需要行为型设计模式?
  5. 行为型模式的核心设计原则
  6. 观察者模式:事件驱动的通知机制
  7. 核心角色与交互流程
  8. 1. 核心角色
  9. 2. 交互流程
  10. 适用场景
  11. 基础实现:同步观察者模式(C++ 示例)
  12. 步骤 1:定义观察者抽象接口
  13. 步骤 2:定义被观察者抽象接口
  14. 步骤 3:实现具体被观察者(气象站)
  15. 步骤 4:实现具体观察者(显示屏、手机 App、报警器)
  16. 步骤 5:客户端使用示例
  17. 运行结果
  18. 进阶优化:线程安全与异步通知
  19. 优化方案 1:线程安全的同步通知(加锁保护)
  20. 优化方案 2:异步通知(使用线程池)
  21. 异步通知测试代码
  22. 异步通知运行结果
  23. 观察者模式的优缺点与避坑指南
  24. 优点
  25. 缺点
  26. 避坑指南
  27. 策略模式:算法的封装与动态切换
  28. 核心角色与设计逻辑
  29. 1. 核心角色
  30. 2. 设计逻辑
  31. 适用场景
  32. 基础实现:电商折扣策略系统(C++ 示例)
  33. 步骤 1:定义策略抽象接口(折扣算法)
  34. 步骤 2:实现具体策略(不同折扣算法)
  35. 步骤 3:实现上下文(订单结算系统)
  36. 步骤 4:客户端使用示例
  37. 运行结果
  38. 策略模式与简单工厂模式的区别
  39. 策略模式的优缺点与避坑指南
  40. 优点
  41. 缺点
  42. 避坑指南
  43. 实战案例:结合观察者模式与策略模式开发智能物流调度系统
  44. 需求分析
  45. 设计思路
  46. 完整实现代码
  47. 代码说明与运行效果
  48. 核心设计亮点
  49. 运行结果(关键片段)
  50. 本章总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • (6-4-02)IMU融合与机体状态估计:综合实战:腿式机器人的IMU关节融合与状态估计(2)
  • AI 产品经理的角色定位与核心能力解析
  • 环形链表、两个数组中的交集与随机链表复制算法解析
  • Flutter 组件 tavily_dart 适配鸿蒙 HarmonyOS 进阶:聚合搜索与语义降噪
  • AutoGenStudio Agent Apps 部署:Windows 代码调用与 Linux REST API 测试
  • 微信 H5 缓存控制:后端重定向与前端强制刷新
  • Python SQLAlchemy ORM 数据库操作指南:安装、模型与 CRUD
  • 20 个 Python 自动化脚本实战:文件管理与办公效率提升
  • Python 爬虫入门:基础类库与实战案例详解
  • MIT 室内场景识别数据集介绍与模型训练实战
  • 基于 Rokid AR 眼镜的聚会游戏助手开发实践
  • ROS 基于 v4l2loopback 虚拟摄像头的 YOLO 目标检测与机器人控制
  • 自然语言处理在医疗健康领域的实战应用
  • NoneBot 与 Lagrange 搭建 QQ 机器人教程
  • 从零搭建 Django + Vue 全栈应用:用户认证篇
  • Linux 线程池封装与实现详解
  • Flutter sse_stream 鸿蒙适配:高并发背压处理与 AI 响应流优化
  • 哈希表原理与实现:线性探测及链地址法
  • OpenClaw 配置飞书机器人与 Kimi 2.5 接入指南
  • Ubuntu 部署 OpenClaw 智能体框架实战指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online