news 2026/2/26 20:00:12

【OpenHarmony】设计模式模块详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【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()

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/19 5:15:58

创业前需要了解哪些市场情况?

创业前需要了解哪些市场情况&#xff1f;春芽惠企总结以下几点↓市场调研是前提&#xff1a;先摸清赛道情况&#xff0c;看看同行竞品的优劣势&#xff0c;明确自身产品或服务的核心差异。精准捕捉目标客户的需求与痛点&#xff0c;才能在竞争中找到突围机会。选对公司类型&…

作者头像 李华
网站建设 2026/2/24 3:36:43

FourierKAN终极指南:构建下一代神经网络层的完整教程

FourierKAN终极指南&#xff1a;构建下一代神经网络层的完整教程 【免费下载链接】FourierKAN 项目地址: https://gitcode.com/GitHub_Trending/fo/FourierKAN 在深度学习领域&#xff0c;传统的线性层配合非线性激活函数的组合已经统治了多年。然而&#xff0c;随着模…

作者头像 李华
网站建设 2026/2/20 12:13:07

Wan2.2-T2V-A14B模型在智能家居场景演示视频制作中的应用

Wan2.2-T2V-A14B模型在智能家居场景演示视频制作中的应用 你有没有想过&#xff0c;一段描述“清晨阳光洒进客厅&#xff0c;智能窗帘缓缓开启&#xff0c;空调自动调节到24度”的文字&#xff0c;下一秒就能变成一段流畅的高清视频&#xff1f;这不再是科幻电影的情节——今天…

作者头像 李华
网站建设 2026/2/25 13:53:56

从配方创新到量产落地:国产PLM系统赋能化工新材料企业数字化跃迁

引言在新材料产业升级与“双碳”战略的双重牵引下&#xff0c;化工新材料行业正迈入数字化转型的深水区。作为技术密集型行业&#xff0c;化工新材料企业的核心链条覆盖前沿配方研发、中试工艺优化、规模化量产、绿色合规管控、终端应用服务等关键环节&#xff0c;长期面临研发…

作者头像 李华
网站建设 2026/2/23 17:29:05

deepseek-r1大模型的本地部署

deepseek-r1大模型的本地部署 第一步&#xff1a;下载ollamaDownload Ollama on Windows 这里下载的是window系统 第二步&#xff1a;下载合适的模型 在ollama官网左上角点击“models”查看模型类别和大小 在本地按winR&#xff0c;输出cmd&#xff0c;打开终端&#xff0c;输…

作者头像 李华
网站建设 2026/2/24 21:25:42

一键生成绘图仪风格线条画:Pintr终极指南

一键生成绘图仪风格线条画&#xff1a;Pintr终极指南 【免费下载链接】pintr Create single line illustrations from your pictures. Get a drawing, SVG or coordinates for a CNC. 项目地址: https://gitcode.com/gh_mirrors/pi/pintr 还在为普通照片缺乏艺术感而烦恼…

作者头像 李华