当前位置: 首页 > news >正文

【OpenHarmony】设计模式模块详解

设计模式模块详解

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


📚 目录

  1. 什么是设计模式?
  2. 模块组件一览
  3. 单例模式 - Singleton
  4. 延迟单例 - DelayedSingleton
  5. 引用延迟单例 - DelayedRefSingleton
  6. 观察者模式 - 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()
实现原理
template<typenameT>classSingleton:publicNoCopyable{public:staticT&GetInstance(){returninstance_;}private:staticT instance_;// 静态成员,程序启动时初始化};template<typenameT>T Singleton<T>::instance_;
使用方式
#include"singleton.h"// 方式1:使用宏声明classConfigManager{DECLARE_SINGLETON(ConfigManager)public:voidLoadConfig(){/* ... */}std::stringGetValue(conststd::string&key){/* ... */}};// 使用ConfigManager&config=Singleton<ConfigManager>::GetInstance();config.LoadConfig();
// 方式2:手动实现classLogger{public:staticLogger&GetInstance(){returnSingleton<Logger>::GetInstance();}voidLog(conststd::string&msg){std::cout<<msg<<std::endl;}private:friendSingleton<Logger>;Logger()=default;~Logger()=default;Logger(constLogger&)=delete;Logger&operator=(constLogger&)=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 实现原理

template<typenameT>classDelayedSingleton:publicNoCopyable{public:staticstd::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;}}returninstance_;}staticvoidDestroyInstance(){std::lock_guard<std::mutex>lock(mutex_);if(instance_!=nullptr){instance_.reset();instance_=nullptr;}}private:staticstd::shared_ptr<T>instance_;staticstd::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 使用方式

#include"singleton.h"classDatabasePool{DECLARE_DELAYED_SINGLETON(DatabasePool)public:voidConnect(){/* ... */}voidQuery(conststd::string&sql){/* ... */}};// 实现构造和析构DatabasePool::DatabasePool(){std::cout<<"数据库连接池创建"<<std::endl;}DatabasePool::~DatabasePool(){std::cout<<"数据库连接池销毁"<<std::endl;}// 使用voidUseDatabasePool(){// 获取实例(首次调用时创建)autopool=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 对比

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

5.4 使用方式

#include"singleton.h"classAppConfig{DECLARE_DELAYED_REF_SINGLETON(AppConfig)public:voidLoad(){/* ... */}std::stringGet(conststd::string&key){return"value";}};AppConfig::AppConfig(){std::cout<<"配置加载"<<std::endl;}AppConfig::~AppConfig(){std::cout<<"配置卸载"<<std::endl;}// 使用voidUseAppConfig(){// 获取引用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 通知流程

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

6.6 使用示例

定义被观察者
#include"observer.h"#include<iostream>usingnamespaceOHOS;// 自定义参数structStockPriceArg:publicObserverArg{std::string symbol;doubleprice;StockPriceArg(conststd::string&s,doublep):symbol(s),price(p){}};// 股票行情(被观察者)classStockMarket:publicObservable{public:voidUpdatePrice(conststd::string&symbol,doubleprice){std::cout<<"股票 "<<symbol<<" 价格更新: "<<price<<std::endl;SetChanged();// 标记状态改变StockPriceArgarg(symbol,price);NotifyObservers(&arg);// 通知所有观察者}};
定义观察者
// 投资者(观察者)classInvestor:publicObserver{public:Investor(conststd::string&name):name_(name){}voidUpdate(constObservable*o,constObserverArg*arg)override{auto*priceArg=dynamic_cast<constStockPriceArg*>(arg);if(priceArg){std::cout<<name_<<" 收到通知: "<<priceArg->symbol<<" = "<<priceArg->price<<std::endl;// 根据价格做出决策if(priceArg->price<100){std::cout<<name_<<": 买入!"<<std::endl;}elseif(priceArg->price>150){std::cout<<name_<<": 卖出!"<<std::endl;}}}private:std::string name_;};
使用
voidObserverDemo(){// 创建被观察者StockMarket market;// 创建观察者autoinvestor1=std::make_shared<Investor>("张三");autoinvestor2=std::make_shared<Investor>("李四");autoinvestor3=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 三种单例对比

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

7.3 何时使用观察者模式?

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

适用场景

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

8. 使用示例与最佳实践

8.1 单例模式最佳实践

✅ 推荐做法
// 1. 使用宏简化声明classMyService{DECLARE_DELAYED_SINGLETON(MyService)public:voidDoWork();};// 2. 正确使用 DelayedSingletonautoservice=DelayedSingleton<MyService>::GetInstance();if(service){// 检查是否创建成功service->DoWork();}// 3. 在适当时机销毁voidCleanup(){DelayedSingleton<MyService>::DestroyInstance();}// 4. 饿汉式用于必须存在的对象classLogger{DECLARE_SINGLETON(Logger)public:voidLog(conststd::string&msg);};
❌ 避免的错误
// 错误1: 手动 new 单例类MyService*service=newMyService();// ❌ 破坏单例// 错误2: 忘记检查 nullptrautoservice=DelayedSingleton<MyService>::GetInstance();service->DoWork();// ❌ 如果内存不足,service 可能为 nullptr// 错误3: 在析构函数中访问其他单例MyService::~MyService(){// ❌ 其他单例可能已经销毁Singleton<Logger>::GetInstance().Log("Service destroyed");}// 错误4: 循环依赖classA{DECLARE_DELAYED_SINGLETON(A)voidInit(){DelayedSingleton<B>::GetInstance();// A 依赖 B}};classB{DECLARE_DELAYED_SINGLETON(B)voidInit(){DelayedSingleton<A>::GetInstance();// B 依赖 A → 💥}};

8.2 观察者模式最佳实践

✅ 推荐做法
// 1. 使用 shared_ptr 管理观察者autoobserver=std::make_shared<MyObserver>();subject.AddObserver(observer);// 2. 在析构前移除观察者classMyObserver:publicObserver{public:~MyObserver(){if(subject_){subject_->RemoveObserver(shared_from_this());}}};// 3. 检查参数类型voidUpdate(constObservable*o,constObserverArg*arg)override{auto*myArg=dynamic_cast<constMyArg*>(arg);if(myArg){// 安全使用}}// 4. 记得 SetChangedvoidNotifyPriceChange(doubleprice){SetChanged();// ✅ 必须先设置NotifyObservers(&arg);}
❌ 避免的错误
// 错误1: 忘记 SetChangedvoidNotifyPriceChange(doubleprice){NotifyObservers(&arg);// ❌ 不会通知任何人!}// 错误2: 在 Update 中修改观察者列表voidUpdate(constObservable*o,constObserverArg*arg)override{o->RemoveObserver(this);// ❌ 可能导致迭代器失效}// 错误3: 观察者泄漏voidSomeFunction(){autoobserver=std::make_shared<MyObserver>();subject.AddObserver(observer);// ❌ 函数结束后 observer 被销毁,但 subject 还持有引用}

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

#include"singleton.h"#include"observer.h"#include<map>#include<string>usingnamespaceOHOS;// 配置变更参数structConfigChangeArg:publicObserverArg{std::string key;std::string oldValue;std::string newValue;};// 配置管理器(单例 + 被观察者)classConfigManager:publicObservable{DECLARE_DELAYED_SINGLETON(ConfigManager)public:voidSet(conststd::string&key,conststd::string&value){std::string oldValue=configs_[key];configs_[key]=value;// 通知观察者SetChanged();ConfigChangeArg arg{key,oldValue,value};NotifyObservers(&arg);}std::stringGet(conststd::string&key){returnconfigs_[key];}private:std::map<std::string,std::string>configs_;};ConfigManager::ConfigManager()=default;ConfigManager::~ConfigManager()=default;// 配置监听器classConfigListener:publicObserver{public:ConfigListener(conststd::string&name):name_(name){}voidUpdate(constObservable*o,constObserverArg*arg)override{auto*configArg=dynamic_cast<constConfigChangeArg*>(arg);if(configArg){std::cout<<name_<<" 检测到配置变更: "<<configArg->key<<" = "<<configArg->newValue<<" (原值: "<<configArg->oldValue<<")"<<std::endl;}}private:std::string name_;};// 使用voidConfigDemo(){autoconfigMgr=DelayedSingleton<ConfigManager>::GetInstance();// 添加监听器autolistener1=std::make_shared<ConfigListener>("UI模块");autolistener2=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()

http://www.jsqmd.com/news/76281/

相关文章:

  • 2025年pet薄膜开关直销厂家推荐榜单:专业薄膜开关‌/导电薄膜开关‌/微波炉薄膜开关源头厂家精选 - 品牌推荐官
  • 3步搞定Go版本管理:从环境混乱到高效开发的终极指南
  • 如何在管家婆网店ERP中创建物流单模板?
  • 2025年中国不锈钢盘管制造企业排名:靠谱的不锈钢盘管制造企 - 工业推荐榜
  • 闪电AI文档转换Lite:离线免费的全能文档处理神器
  • 2025年质量好的抽屉阻尼隐藏轨/橱柜阻尼隐藏轨厂家实力及用户口碑排行榜 - 行业平台推荐
  • IonicRange滑动控件全解析
  • IonicTab入门:打造高效导航应用
  • 2025年多乙烯多胺环保型厂家TOP5权威推荐:源头供应企业 - 工业品牌热点
  • 管理系统权限管理(菜单、页面、按钮)react+redux/vue3 pinia实现方式
  • 2025年质量好的女士护手霜TOP实力厂家推荐榜 - 行业平台推荐
  • 12、深入探索Shell环境定制与任务管理
  • iOS调试救星:告别真机测试兼容性难题的终极指南
  • 东莞注塑加工厂哪里多
  • C++ 模板进阶:解锁泛型编程的高级玩法 - 详解
  • 助听器最新科技盘点:西嘉音聚平台,聚焦嘈杂环境多人对话 - 品牌排行榜单
  • windows部署Open-AutoGLM模型
  • 3分钟极速部署OpenMetadata元数据平台的完整指南
  • 永别了,控制台!
  • 2025年评价高的毛绒玩具激光切割机/自动送料激光切割机厂家实力及用户口碑排行榜 - 品牌宣传支持者
  • 机械故障诊断与振动信号数据集:工业设备健康监测的终极指南
  • TradingAgents-CN配置管理实战:从新手到专家的7个关键步骤与真实案例解析
  • 5大革新特性:解析阿里Wan2.2-Animate-14B电影级动画生成技术
  • MarchingCases marchingcubes算法15种情况的展示
  • 4、深入探索I/O、重定向、管道和过滤器
  • 千万不能错过!这家外卖点单小程序技术领先机构,竟然让商家收入
  • 知乎内容永久保存神器:一键备份所有回答、文章和想法 [特殊字符]
  • Windows系统pgvector一键部署攻略:告别编译烦恼,轻松开启向量搜索
  • Node.js ESC/POS打印控制终极指南:node-escpos模块完整教程
  • ChromePass终极指南:3步快速找回Chrome浏览器所有保存密码