news 2026/4/16 15:50:35

【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/4/15 18:19:20

AMD Ryzen处理器调优神器:SMUDebugTool深度体验指南

还在为AMD处理器性能调优而苦恼吗&#xff1f;SMUDebugTool作为一款专业的硬件调试工具&#xff0c;为您打开了深入Ryzen平台底层的大门。无论您是硬件发烧友还是系统开发者&#xff0c;这款工具都能让您轻松掌握处理器核心参数&#xff0c;实现精准的性能优化。 【免费下载链接…

作者头像 李华
网站建设 2026/4/15 18:56:12

行业动态 | 一周银发产业大事件速览

​一周银发产业大事件速览12月12日星期五1养老服务京东App正式上线市民服务&#xff0c;涵盖多项便民服务功能阳光大姐集团等合作聚焦家政养老服务人才职业认证中国平安旗下平安居家养老服务体系将再度升级国民养老与安联投资首个战略合作项目落地保利养老中标广州居家社区养老…

作者头像 李华
网站建设 2026/4/16 12:21:04

Node.js ESC/POS打印控制终极指南:node-escpos模块完整教程

Node.js ESC/POS打印控制终极指南&#xff1a;node-escpos模块完整教程 【免费下载链接】node-escpos &#x1f5a8;️ ESC/POS Printer driver for Node.js 项目地址: https://gitcode.com/gh_mirrors/no/node-escpos &#x1f3af; 在现代商业应用中&#xff0c;打印功…

作者头像 李华
网站建设 2026/4/16 12:17:31

永别了,控制台!

本文已收录在Github&#xff0c;关注我&#xff0c;紧跟本系列专栏文章&#xff0c;咱们下篇再续&#xff01; &#x1f680; 魔都架构师 | 全网30W技术追随者&#x1f527; 大厂分布式系统/数据中台实战专家&#x1f3c6; 主导交易系统百万级流量调优 & 车联网平台架构&a…

作者头像 李华
网站建设 2026/4/16 12:16:17

一.AI前置知识了解

一.C和AI直接的关系 二.项目背景 和 名词解释 1.项目背景 2.名词解释 三.DeepSeek、ChatGPT、Gemini使用 1.deepseek使用 deepseek官网&#xff1a;https://www.deepseek.com/ API链接:https://mp.weixin.qq.com/s/ohsU1xRrYu9xcVD7qu5lNw 模型训练有一个截至日期,所以联网搜…

作者头像 李华
网站建设 2026/4/16 12:15:31

Wireshark抓包分析实战:从入门到排查网络故障

本文详解Wireshark的核心功能,从抓包基础到实际故障排查,带你掌握网络分析的必备技能。 前言 网络出问题了,ping不通、连接超时、速度慢…这时候怎么排查? 抓包分析是网络排查的终极武器。不管问题多复杂,抓个包看看数据流,真相就在眼前。 Wireshark是最强大的抓包工具…

作者头像 李华