【OpenHarmony】设计模式模块详解

设计模式模块详解

🎨 一句话概括:设计模式模块提供了单例模式和观察者模式的现成实现,让你的代码更优雅、更易维护。


📚 目录

  1. 什么是设计模式?
  2. 模块组件一览
  3. [单例模式 - Singleton](#单例模式 - Singleton)
  4. [延迟单例 - DelayedSingleton](#延迟单例 - DelayedSingleton)
  5. [引用延迟单例 - DelayedRefSingleton](#引用延迟单例 - DelayedRefSingleton)
  6. [观察者模式 - Observer](#观察者模式 - Observer)
  7. 模式对比与选择
  8. 使用示例与最佳实践

1. 什么是设计模式?

1.1 通俗理解

设计模式就像建筑图纸 📐:

  • 不用每次都从零开始设计
  • 经过验证的解决方案
  • 让其他开发者一看就懂

1.2 c_utils 提供的设计模式

单例变体 设计模式 Singleton
饿汉式 DelayedSingleton
懒汉式+智能指针 DelayedRefSingleton
懒汉式+裸指针 单例模式
Singleton 观察者模式
Observer


2. 模块组件一览

组件 类型 特点 线程安全
Singleton 饿汉式单例 程序启动时创建
DelayedSingleton 懒汉式单例 首次使用时创建,智能指针管理
DelayedRefSingleton 懒汉式单例 首次使用时创建,裸指针管理
Observable 被观察者 维护观察者列表,发送通知
Observer 观察者 接收通知,执行更新 -

3. 单例模式 - Singleton

3.1 什么是单例模式?

单例模式确保一个类只有一个实例,并提供全局访问点。
单例类 唯一实例 GetInstance GetInstance GetInstance 普通类 对象1 new MyClass new MyClass 对象2 new MyClass 对象3

3.2 Singleton(饿汉式)

特点:程序启动时就创建实例,简单但可能浪费资源。
Singleton<T> -static T instance_ +GetInstance()

实现原理
cpp 复制代码
template<typename T>
class Singleton : public NoCopyable {
public:
    static T& GetInstance() { return instance_; }
private:
    static T instance_;  // 静态成员,程序启动时初始化
};

template<typename T>
T Singleton<T>::instance_;
使用方式
cpp 复制代码
#include "singleton.h"

// 方式1:使用宏声明
class ConfigManager {
    DECLARE_SINGLETON(ConfigManager)
public:
    void LoadConfig() { /* ... */ }
    std::string GetValue(const std::string& key) { /* ... */ }
};

// 使用
ConfigManager& config = Singleton<ConfigManager>::GetInstance();
config.LoadConfig();
cpp 复制代码
// 方式2:手动实现
class Logger {
public:
    static Logger& GetInstance() {
        return Singleton<Logger>::GetInstance();
    }
    
    void Log(const std::string& msg) {
        std::cout << msg << std::endl;
    }
    
private:
    friend Singleton<Logger>;
    Logger() = default;
    ~Logger() = default;
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;
};

// 使用
Logger::GetInstance().Log("Hello");

3.3 生命周期

main() 静态初始化 Singleton实例 程序启动 创建实例 实例已存在 GetInstance() 返回引用 GetInstance() 返回同一引用 程序结束 销毁实例 main() 静态初始化 Singleton实例


4. 延迟单例 - DelayedSingleton

4.1 概述

DelayedSingleton 是懒汉式单例,特点:

  • 延迟创建:首次调用 GetInstance 时才创建
  • 🔒 线程安全:双重检查锁定(DCL)
  • 🧹 自动管理:使用 shared_ptr 管理内存

4.2 类结构

DelayedSingleton<T> -static std::shared_ptr<T> instance_ -static std::mutex mutex_ +GetInstance() +DestroyInstance()

4.3 实现原理

cpp 复制代码
template<typename T>
class DelayedSingleton : public NoCopyable {
public:
    static std::shared_ptr<T> GetInstance() {
        if (instance_ == nullptr) {                    // 第一次检查(无锁)
            std::lock_guard<std::mutex> lock(mutex_);  // 加锁
            if (instance_ == nullptr) {                // 第二次检查(有锁)
                std::shared_ptr<T> temp(new (std::nothrow) T);
                instance_ = temp;
            }
        }
        return instance_;
    }
    
    static void DestroyInstance() {
        std::lock_guard<std::mutex> lock(mutex_);
        if (instance_ != nullptr) {
            instance_.reset();
            instance_ = nullptr;
        }
    }
    
private:
    static std::shared_ptr<T> instance_;
    static std::mutex mutex_;
};

4.4 双重检查锁定(DCL)

否 是 否 是 GetInstance instance_ == nullptr? 返回 instance_ 加锁 instance_ == nullptr? 解锁 创建实例 instance_ = 新实例

为什么需要两次检查?
线程1 线程2 互斥锁 instance_ nullptr 检查1: nullptr? ✓ 检查1: nullptr? ✓ 获取锁 🔒 等待锁... 检查2: nullptr? ✓ 创建实例 释放锁 🔓 获取锁 🔒 检查2: nullptr? ✗ 不再创建! 释放锁 🔓 线程1 线程2 互斥锁 instance_

4.5 使用方式

cpp 复制代码
#include "singleton.h"

class DatabasePool {
    DECLARE_DELAYED_SINGLETON(DatabasePool)
public:
    void Connect() { /* ... */ }
    void Query(const std::string& sql) { /* ... */ }
};

// 实现构造和析构
DatabasePool::DatabasePool() {
    std::cout << "数据库连接池创建" << std::endl;
}

DatabasePool::~DatabasePool() {
    std::cout << "数据库连接池销毁" << std::endl;
}

// 使用
void UseDatabasePool() {
    // 获取实例(首次调用时创建)
    auto pool = DelayedSingleton<DatabasePool>::GetInstance();
    pool->Connect();
    pool->Query("SELECT * FROM users");
    
    // 可以主动销毁
    DelayedSingleton<DatabasePool>::DestroyInstance();
}

4.6 shared_ptr 的优势

shared_ptr shared_ptr GetInstance GetInstance 引用计数管理 自动释放 普通指针 裸指针 GetInstance GetInstance 谁来 delete? 可能泄漏或重复释放


5. 引用延迟单例 - DelayedRefSingleton

5.1 概述

DelayedRefSingleton 与 DelayedSingleton 类似,但:

  • 📌 返回引用:而不是智能指针
  • ⚠️ 手动管理:不会自动销毁

5.2 类结构

DelayedRefSingleton<T> -static T* instance_ -static std::mutex mutex_ +GetInstance()

5.3 与 DelayedSingleton 对比

特性 DelayedSingleton DelayedRefSingleton
返回类型 shared_ptr<T> T&
内存管理 自动(引用计数) 手动
DestroyInstance ✅ 有 ❌ 无
使用方式 -> 访问 . 访问
适用场景 需要灵活管理生命周期 全程序生命周期

5.4 使用方式

cpp 复制代码
#include "singleton.h"

class AppConfig {
    DECLARE_DELAYED_REF_SINGLETON(AppConfig)
public:
    void Load() { /* ... */ }
    std::string Get(const std::string& key) { return "value"; }
};

AppConfig::AppConfig() {
    std::cout << "配置加载" << std::endl;
}

AppConfig::~AppConfig() {
    std::cout << "配置卸载" << std::endl;
}

// 使用
void UseAppConfig() {
    // 获取引用
    AppConfig& config = DelayedRefSingleton<AppConfig>::GetInstance();
    config.Load();
    std::string value = config.Get("key");
}

6. 观察者模式 - Observer

6.1 什么是观察者模式?

观察者模式定义了对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会收到通知。
观察者模式 通知 通知 通知 Observer1 Subject
被观察者 Observer2 Observer3

6.2 生活中的例子

微信公众号 推送文章 推送文章 推送文章 关注 关注 关注 用户1
Observer 公众号
Observable 用户2
Observer 用户3
Observer

6.3 类结构

通知 1 * 使用 接收 <<struct>> ObserverArg +virtual ~ObserverArg() Observable #std::set<shared_ptr>Observer<> obs #std::mutex mutex_ -bool changed_ +AddObserver(o) +RemoveObserver(o) +RemoveAllObservers() +NotifyObservers() +NotifyObservers(arg) +GetObserversCount() : int #HasChanged() : bool #SetChanged() #ClearChanged() <<interface>> Observer +Update(o, arg) : void

6.4 核心方法

Observable(被观察者)
方法 说明
AddObserver(o) 添加观察者
RemoveObserver(o) 移除观察者
RemoveAllObservers() 移除所有观察者
NotifyObservers() 通知所有观察者(无参数)
NotifyObservers(arg) 通知所有观察者(带参数)
SetChanged() 标记状态已改变
ClearChanged() 清除改变标记
HasChanged() 检查是否有改变
Observer(观察者)
方法 说明
Update(o, arg) 收到通知时的回调(纯虚函数)

6.5 通知流程

Subject Observer1 Observer2 状态改变 SetChanged() NotifyObservers(arg) ClearChanged() Update(this, arg) 处理通知 Update(this, arg) 处理通知 不通知 alt [HasChanged() == true] [HasChanged() == false] Subject Observer1 Observer2

6.6 使用示例

定义被观察者
cpp 复制代码
#include "observer.h"
#include <iostream>

using namespace OHOS;

// 自定义参数
struct StockPriceArg : public ObserverArg {
    std::string symbol;
    double price;
    
    StockPriceArg(const std::string& s, double p) 
        : symbol(s), price(p) {}
};

// 股票行情(被观察者)
class StockMarket : public Observable {
public:
    void UpdatePrice(const std::string& symbol, double price) {
        std::cout << "股票 " << symbol << " 价格更新: " << price << std::endl;
        
        SetChanged();  // 标记状态改变
        
        StockPriceArg arg(symbol, price);
        NotifyObservers(&arg);  // 通知所有观察者
    }
};
定义观察者
cpp 复制代码
// 投资者(观察者)
class Investor : public Observer {
public:
    Investor(const std::string& name) : name_(name) {}
    
    void Update(const Observable* o, const ObserverArg* arg) override {
        auto* priceArg = dynamic_cast<const StockPriceArg*>(arg);
        if (priceArg) {
            std::cout << name_ << " 收到通知: " 
                      << priceArg->symbol << " = " << priceArg->price 
                      << std::endl;
            
            // 根据价格做出决策
            if (priceArg->price < 100) {
                std::cout << name_ << ": 买入!" << std::endl;
            } else if (priceArg->price > 150) {
                std::cout << name_ << ": 卖出!" << std::endl;
            }
        }
    }
    
private:
    std::string name_;
};
使用
cpp 复制代码
void ObserverDemo() {
    // 创建被观察者
    StockMarket market;
    
    // 创建观察者
    auto investor1 = std::make_shared<Investor>("张三");
    auto investor2 = std::make_shared<Investor>("李四");
    auto investor3 = std::make_shared<Investor>("王五");
    
    // 注册观察者
    market.AddObserver(investor1);
    market.AddObserver(investor2);
    market.AddObserver(investor3);
    
    std::cout << "观察者数量: " << market.GetObserversCount() << std::endl;
    
    // 更新价格,自动通知所有观察者
    market.UpdatePrice("AAPL", 95.0);
    std::cout << "---" << std::endl;
    market.UpdatePrice("AAPL", 160.0);
    
    // 移除一个观察者
    market.RemoveObserver(investor2);
    std::cout << "---" << std::endl;
    market.UpdatePrice("AAPL", 120.0);
}
输出
复制代码
观察者数量: 3
股票 AAPL 价格更新: 95
张三 收到通知: AAPL = 95
张三: 买入!
李四 收到通知: AAPL = 95
李四: 买入!
王五 收到通知: AAPL = 95
王五: 买入!
---
股票 AAPL 价格更新: 160
张三 收到通知: AAPL = 160
张三: 卖出!
李四 收到通知: AAPL = 160
李四: 卖出!
王五 收到通知: AAPL = 160
王五: 卖出!
---
股票 AAPL 价格更新: 120
张三 收到通知: AAPL = 120
王五 收到通知: AAPL = 120

7. 模式对比与选择

7.1 单例模式选择指南

程序启动 首次使用 是 否 智能指针 引用 需要单例 何时创建? Singleton
饿汉式 需要销毁? DelayedSingleton
智能指针 返回类型? DelayedRefSingleton
裸指针

7.2 三种单例对比

特性 Singleton DelayedSingleton DelayedRefSingleton
创建时机 程序启动 首次使用 首次使用
线程安全 ✅ DCL ✅ DCL
返回类型 T& shared_ptr T&
可销毁
内存管理 自动 自动 手动
性能 最高 中等 中等
适用场景 必须存在的全局对象 可选的全局对象 全程序生命周期

7.3 何时使用观察者模式?

flowchart TB A[场景分析] --> B{一对多关系?} B -->|否| C[不适用] B -->|是| D{状态变化需通知?} D -->|否| C D -->|是| E{松耦合要求?} E -->|否| F[直接调用可能更简单] E -->|是| G[✅ 使用观察者模式]

适用场景

  • 📰 消息订阅系统
  • 📊 数据绑定(MVC/MVVM)
  • 🔔 事件通知
  • 📈 股票行情推送
  • 💬 聊天室消息广播

8. 使用示例与最佳实践

8.1 单例模式最佳实践

✅ 推荐做法
cpp 复制代码
// 1. 使用宏简化声明
class MyService {
    DECLARE_DELAYED_SINGLETON(MyService)
public:
    void DoWork();
};

// 2. 正确使用 DelayedSingleton
auto service = DelayedSingleton<MyService>::GetInstance();
if (service) {  // 检查是否创建成功
    service->DoWork();
}

// 3. 在适当时机销毁
void Cleanup() {
    DelayedSingleton<MyService>::DestroyInstance();
}

// 4. 饿汉式用于必须存在的对象
class Logger {
    DECLARE_SINGLETON(Logger)
public:
    void Log(const std::string& msg);
};
❌ 避免的错误
cpp 复制代码
// 错误1: 手动 new 单例类
MyService* service = new MyService();  // ❌ 破坏单例

// 错误2: 忘记检查 nullptr
auto service = DelayedSingleton<MyService>::GetInstance();
service->DoWork();  // ❌ 如果内存不足,service 可能为 nullptr

// 错误3: 在析构函数中访问其他单例
MyService::~MyService() {
    // ❌ 其他单例可能已经销毁
    Singleton<Logger>::GetInstance().Log("Service destroyed");
}

// 错误4: 循环依赖
class A {
    DECLARE_DELAYED_SINGLETON(A)
    void Init() {
        DelayedSingleton<B>::GetInstance();  // A 依赖 B
    }
};
class B {
    DECLARE_DELAYED_SINGLETON(B)
    void Init() {
        DelayedSingleton<A>::GetInstance();  // B 依赖 A → 💥
    }
};

8.2 观察者模式最佳实践

✅ 推荐做法
cpp 复制代码
// 1. 使用 shared_ptr 管理观察者
auto observer = std::make_shared<MyObserver>();
subject.AddObserver(observer);

// 2. 在析构前移除观察者
class MyObserver : public Observer {
public:
    ~MyObserver() {
        if (subject_) {
            subject_->RemoveObserver(shared_from_this());
        }
    }
};

// 3. 检查参数类型
void Update(const Observable* o, const ObserverArg* arg) override {
    auto* myArg = dynamic_cast<const MyArg*>(arg);
    if (myArg) {
        // 安全使用
    }
}

// 4. 记得 SetChanged
void NotifyPriceChange(double price) {
    SetChanged();         // ✅ 必须先设置
    NotifyObservers(&arg);
}
❌ 避免的错误
cpp 复制代码
// 错误1: 忘记 SetChanged
void NotifyPriceChange(double price) {
    NotifyObservers(&arg);  // ❌ 不会通知任何人!
}

// 错误2: 在 Update 中修改观察者列表
void Update(const Observable* o, const ObserverArg* arg) override {
    o->RemoveObserver(this);  // ❌ 可能导致迭代器失效
}

// 错误3: 观察者泄漏
void SomeFunction() {
    auto observer = std::make_shared<MyObserver>();
    subject.AddObserver(observer);
    // ❌ 函数结束后 observer 被销毁,但 subject 还持有引用
}

8.3 综合示例:配置管理系统

cpp 复制代码
#include "singleton.h"
#include "observer.h"
#include <map>
#include <string>

using namespace OHOS;

// 配置变更参数
struct ConfigChangeArg : public ObserverArg {
    std::string key;
    std::string oldValue;
    std::string newValue;
};

// 配置管理器(单例 + 被观察者)
class ConfigManager : public Observable {
    DECLARE_DELAYED_SINGLETON(ConfigManager)
public:
    void Set(const std::string& key, const std::string& value) {
        std::string oldValue = configs_[key];
        configs_[key] = value;
        
        // 通知观察者
        SetChanged();
        ConfigChangeArg arg{key, oldValue, value};
        NotifyObservers(&arg);
    }
    
    std::string Get(const std::string& key) {
        return configs_[key];
    }
    
private:
    std::map<std::string, std::string> configs_;
};

ConfigManager::ConfigManager() = default;
ConfigManager::~ConfigManager() = default;

// 配置监听器
class ConfigListener : public Observer {
public:
    ConfigListener(const std::string& name) : name_(name) {}
    
    void Update(const Observable* o, const ObserverArg* arg) override {
        auto* configArg = dynamic_cast<const ConfigChangeArg*>(arg);
        if (configArg) {
            std::cout << name_ << " 检测到配置变更: " 
                      << configArg->key << " = " << configArg->newValue 
                      << " (原值: " << configArg->oldValue << ")" 
                      << std::endl;
        }
    }
    
private:
    std::string name_;
};

// 使用
void ConfigDemo() {
    auto configMgr = DelayedSingleton<ConfigManager>::GetInstance();
    
    // 添加监听器
    auto listener1 = std::make_shared<ConfigListener>("UI模块");
    auto listener2 = std::make_shared<ConfigListener>("网络模块");
    
    configMgr->AddObserver(listener1);
    configMgr->AddObserver(listener2);
    
    // 修改配置
    configMgr->Set("theme", "dark");
    configMgr->Set("language", "zh-CN");
    
    // 清理
    configMgr->RemoveAllObservers();
    DelayedSingleton<ConfigManager>::DestroyInstance();
}

📊 API 速查表

Singleton 宏

说明
DECLARE_SINGLETON(MyClass) 声明为饿汉式单例
DECLARE_DELAYED_SINGLETON(MyClass) 声明为延迟单例(shared_ptr)
DECLARE_DELAYED_REF_SINGLETON(MyClass) 声明为延迟引用单例

Singleton 类

方法 说明 返回值
Singleton<T>::GetInstance() 获取实例 T&
DelayedSingleton<T>::GetInstance() 获取实例 shared_ptr
DelayedSingleton<T>::DestroyInstance() 销毁实例 void
DelayedRefSingleton<T>::GetInstance() 获取实例 T&

Observable 类

方法 说明
AddObserver(o) 添加观察者
RemoveObserver(o) 移除观察者
RemoveAllObservers() 移除所有观察者
NotifyObservers() 通知观察者(无参数)
NotifyObservers(arg) 通知观察者(带参数)
GetObserversCount() 获取观察者数量
SetChanged() 设置改变标记
ClearChanged() 清除改变标记
HasChanged() 检查改变标记

Observer 类

方法 说明
Update(o, arg) 接收通知的回调(纯虚函数)

🎯 总结

记住这三点

  1. 饿汉式 简单高效,懒汉式节省资源
  2. DelayedSingleton 用 shared_ptr,可以销毁;DelayedRefSingleton 用裸指针,不能销毁
  3. 观察者模式 通知前必须调用 SetChanged()

相关推荐
biter down2 小时前
C++ 解决海量数据 TopK 问题:小根堆高效解法
c++·算法
程芯带你刷C语言简单算法题2 小时前
Day28~实现strlen、strcpy、strncpy、strcat、strncat
c语言·c++·算法·c
一个不知名程序员www2 小时前
算法学习入门--- 树(C++)
c++·算法
Simon席玉3 小时前
C++的命名重整
开发语言·c++·华为·harmonyos·arkts
仰泳的熊猫3 小时前
1148 Werewolf - Simple Version
数据结构·c++·算法·pat考试
十五年专注C++开发3 小时前
同一线程有两个boost::asio::io_context可以吗?
c++·boost·asio·异步编程·io_context
xlq223223 小时前
26 avl树(下)
c++
郝学胜-神的一滴4 小时前
深入理解OpenGL VBO:原理、封装与性能优化
c++·程序人生·性能优化·图形渲染
埃伊蟹黄面4 小时前
模拟算法思想
c++·算法·leetcode