news 2025/12/24 22:29:53

【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进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/22 18:23:17

MarchingCases marchingcubes算法15种情况的展示

一&#xff1a;主要的知识点 1、说明 本文只是教程内容的一小段&#xff0c;因博客字数限制&#xff0c;故进行拆分。主教程链接&#xff1a;vtk教程——逐行解析官网所有Python示例-CSDN博客 2、知识点纪要 本段代码主要涉及的有①MarchingCubes等值面重建的原理展示 二&a…

作者头像 李华
网站建设 2025/12/22 20:42:37

Java IO 实战学习指南:从基础到进阶(附代码实操)

Java IO 实战学习指南&#xff1a;从基础到进阶&#xff08;附代码实操&#xff09; Java IO&#xff08;输入/输出&#xff09;是Java开发的核心基础&#xff0c;负责程序与外部设备&#xff08;文件、网络、键盘等&#xff09;的数据交互。很多初学者觉得IO类繁多、流概念抽象…

作者头像 李华
网站建设 2025/12/24 10:43:43

Docker命令合集详解

总结的相对全面且详细的 Docker 和 Docker Compose 命令合集。为了方便查阅&#xff0c;我将其分为 基础/镜像管理、容器操作、Docker Compose 编排 以及 常用参数详解 四个部分。第一部分&#xff1a;Docker 基础与镜像命令 (Images) 镜像&#xff08;Image&#xff09;是容器…

作者头像 李华
网站建设 2025/12/22 18:13:15

3分钟极速部署OpenMetadata元数据平台的完整指南

3分钟极速部署OpenMetadata元数据平台的完整指南 【免费下载链接】OpenMetadata 开放标准的元数据。一个发现、协作并确保数据正确的单一地点。 项目地址: https://gitcode.com/GitHub_Trending/op/OpenMetadata 一键启动配置&#xff0c;快速搭建企业级数据治理平台。本…

作者头像 李华
网站建设 2025/12/24 2:37:28

11、深入探索Bash脚本:自动完成与环境定制

深入探索Bash脚本:自动完成与环境定制 1. 为自定义应用编写Bash自动完成功能 当使用 complete -r 命令时,如果没有指定 command_name 作为参数,所有的自动完成规范都会被移除: $ complete -r $ completeBash-completion包并不为外部工具提供自动完成功能。若要为有…

作者头像 李华
网站建设 2025/12/12 11:06:20

中文医学基准测试题库数据集:28万条标准化JSON格式医师考试题目与临床案例分析,覆盖28个医学专业领域,用于医学AI模型训练、临床决策支持系统开发、医学知识问答系统构建、医学教育辅助工具优化

中文医学基准测试题库数据集&#xff1a;28万条标准化JSON格式医师考试题目与临床案例分析&#xff0c;覆盖28个医学专业领域&#xff0c;用于医学AI模型训练、临床决策支持系统开发、医学知识问答系统构建、医学教育辅助工具优化 引言与背景 在人工智能技术快速发展的今天&a…

作者头像 李华