DAB实现中用到的主要设计模式
DAB C++ 版本设计模式应用实践
1. 命令模式 (Command Pattern)
设计目标
- 模块解耦:实现各模块独立编译、测试、运行,消除模块间直接依赖
- 扩展准备:为桥接模式实现奠定基础
- 依赖倒置:通过命令对象反转模块依赖方向
- 耦合降低:将模块间耦合简化为命令对象耦合
1.1 MQTT 模块实现
#pragma once
#include <string>
#include <vector>
#include <functional>
/**
* @class HiMqttClient
* @brief MQTT 客户端核心类,提供连接管理、消息发布订阅等功能
*
* @note 采用命令模式实现消息处理回调机制
*/
class HiMqttClient {
public:
// 连接管理接口
static void start(const char* ip, int port, const char* user,
const char* password, const char* clientId);
static void stop();
// 消息管理接口
static void subscribe(const std::vector<std::string>& topics);
static bool publish(const char* topic, const char* body);
// 命令模式回调设置
static void onTopic(const std::function<void(const char*, const char*,
const char*, const char*)>& func);
};
设计亮点:
- 通过
onTopic()设置命令对象实现消息处理解耦 - 支持模块独立单元测试
- 消除与其他业务模块的循环依赖
1.2 Topic 处理器实现
#pragma once
#include <map>
#include <functional>
#include "context/dab_context.h"
/**
* @class TopicHandler
* @brief 基于命令模式的主题处理器
*
* @note 使用注册机制替代传统 switch-case 分支处理
*/
class TopicHandler {
public:
// 生命周期管理
static void init(int maxThreads);
static void destroy();
// 命令注册接口
static void registerHandler(const std::map<std::string,
std::function<void(DABContext&)>>& handles);
// 统一消息入口
static void onTopic(const char* topic, const char* body,
const char* response_topic, const char* correlation_data);
};
创新点:
- 动态注册机制实现处理逻辑可配置化
- 统一消息入口简化调用链路
- 天然支持多线程处理
1.3 上下文对象设计
#pragma once
#include "context/dab_status.h"
#include "context/dab_request.h"
#include "context/dab_response.h"
/**
* @class DABContext
* @brief 请求处理上下文对象
*
* @note 采用命令模式封装消息发布功能
*/
class DABContext {
public:
// 状态管理接口
bool is_ok() const;
void success();
void clientFail(const char* out_log, const char* inner_log = nullptr);
// 消息发布命令接口
static void setPublishFunc(const std::function<void(const char*, const char*)>& func);
static void publish(DABContext& context);
// 数据成员
DABStatus status;
DABRequest request;
DABResponse response;
};
技术优势:
- 隐藏 MQTT 实现细节
- 支持多种消息发布策略
- 上下文自包含设计简化单元测试
1.4 日志模块实现
#pragma once
#include <functional>
/**
* @enum DABLogLevel
* @brief 日志级别枚举定义
*/
enum class DABLogLevel { INFO, WARNING, ERROR, FATAL, ALWAYS };
namespace dab {
/**
* @brief 日志回调设置接口
* @param callback 日志处理函数原型:
* void(日志级别, 文件名, 函数名, 行号, 日志内容)
*/
void set_log_callback(std::function<void(DABLogLevel, const char*,
const char*, int, const char*)> callback);
// 日志宏定义
#define DABLOG_INFO(...) dab::writeLog(DABLogLevel::INFO, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#define DAB_ASSERT(expr, desc) \
do { if (!(expr)) { \
dab::on_assert_fail(__FILE__, __FUNCTION__, __LINE__); \
}} while(0)
}
核心价值:
- 灵活适配不同日志实现
- 支持运行时日志策略切换
- 提供丰富的调试信息
2. 桥接模式 (Bridge Pattern)
设计目标
- 架构解耦:分离抽象与具体实现
- 独立演进:各模块可独立变化
- 统一接口:提供标准化服务能力
系统桥接实现
void publish(const char* topic, const char* body) {
HiMqttClient::publish(topic, body);
}
extern "C" int runDabService() {
// 初始化各模块
TopicHandler::init(DABProperties::max_handle_threads);
DABHandler::init();
// 桥接关键点
HiMqttClient::onTopic(TopicHandler::onTopic);
DABContext::setPublishFunc(publish);
// 订阅与注册
HiMqttClient::subscribe(DABHandler::getTopics());
TopicHandler::registerHandler(DABHandler::getTopicHandles());
// 启动服务
HiMqttClient::start(DABProperties::mqtt_ip.c_str(),
DABProperties::mqtt_port, ...);
return 0;
}
桥接优势:
- 业务逻辑与通信协议解耦
- 模块间通过抽象接口通信
- 新增协议支持成本最低化
3. 适配器模式 (Adapter Pattern)
设计目标
- 接口标准化:统一不同系统的接口规范
- 依赖倒置:反转系统接口依赖方向
- 扩展支持:为策略模式实施奠定基础
典型应用
- 日志适配器:将系统日志接口转换为 DAB 标准日志接口
- 服务适配:封装平台特性接口为统一服务接口
适配收益:
- 业务代码不依赖具体实现
- 新增平台支持只需实现适配器
- 保持核心逻辑稳定性
4. 策略模式 (Strategy Pattern)
应用场景
| 场景 | 实现策略 | 优势 |
|---|---|---|
| 电视环境 | 真实硬件接口实现 | 完整功能支持 |
| 云端环境 | Mock 接口实现 | 无硬件依赖的自动化测试 |
| 单元测试 | 内存型轻量实现 | 快速测试执行 |
策略配置
// 测试环境初始化示例
void dabInit() {
DABContext::setPublishFunc([](const char* t, const char* b) {
DABLOG_ALWAYS("Test Publish: %s -> %s", t, b);
});
TopicHandler::registerHandler({
{"test/topic1", [](DABContext& ctx){ /* Mock处理逻辑 */ }},
{"test/topic2", [](DABContext& ctx){ /* Mock处理逻辑 */ }}
});
}
策略优势:
- 运行时动态切换实现
- 环境隔离保证测试可靠性
- 并行支持多种部署方案
5.单例模式
在DAB的实现中,有意回避了单例模式,使用静态类代替。
```cpp
class TopicHandler {
public:
static void init(int maxThreads); // 显式初始化
static void destroy(); // 显式资源释放
static void registerHandler(/*...*/);
TopicHandler() = delete; // 禁止实例化
};
```
**设计考量**:
1. **生命周期可控**:通过`init()`/`destroy()`明确管理资源
2. **测试友好**:支持不同测试用例的独立初始化
3. **避免全局状态**:每个模块维护自身静态数据
4. **编译期约束**:`= delete`禁止非法操作
**对比传统单例**:
* 不强制全局唯一实例
* 无隐式初始化顺序问题
* 支持多环境配置(测试/生产)
6. 测试体系设计
1. 测试环境搭建
#include <gtest/gtest.h>
#include "dab/dab_api.h"
// 全局测试环境类
class TestEnv : public testing::Environment {
public:
void SetUp() override { dabInit(); } // 测试用例初始化
void TearDown() override { dabDestory(); } // 测试资源回收
};
// 核心初始化逻辑
namespace {
// 模拟消息发布函数
void publish(const char* topic, const char* body) {
DABLOG_ALWAYS("[TEST] Topic:%s\nPayload:%s", topic, body);
}
void dabInit() {
DABProperties::device_id = "TEST_DEVICE"; // 设置测试设备ID
TopicHandler::init(5); // 初始化消息处理线程池
DABHandler::init(); // 业务处理器初始化
DABContext::setPublishFunc(publish); // 注入模拟发布器
// 注册Topic处理函数
TopicHandler::registerHandler(DABHandler::getTopicHandles());
}
void dabDestory() {
TopicHandler::destroy(); // 清理消息处理器
DABHandler::destroy(); // 清理业务处理器
}
}
// 测试主入口
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
testing::AddGlobalTestEnvironment(new TestEnv);
return RUN_ALL_TESTS();
}
2. 设计模式应用解析
| 设计模式 | 应用场景 | 实现要点 |
|---|---|---|
| 命令模式 | 消息处理函数注册 | 通过registerHandler注册处理闭包 |
| 桥接模式 | 业务处理与MQTT通信解耦 | setPublishFunc实现协议隔离 |
| 策略模式 | 测试环境与生产环境配置切换 | DABProperties动态配置 |
3.测试辅助工具实现
1. Topic处理工具类
namespace {
// 生成标准Topic格式
std::string formatTopic(const std::string& baseTopic) {
std::ostringstream oss;
oss << "dab/" << DABProperties::device_id << "/" << baseTopic;
return oss.str();
}
}
// 统一测试入口函数
void onTopicTest(const std::string& topic, const std::string& request) {
TopicHandler::onTopic(
formatTopic(topic).c_str(), // 格式化请求Topic
request.c_str(), // 测试请求载荷
"_response/" + formatTopic(topic).c_str(), // 响应Topic
"" // 关联数据
);
}
2. 工具类设计亮点
- Topic规范化:自动添加设备ID前缀
- 响应隔离:生成专用的响应Topic通道
- 异常防护:内置空指针检查等安全机制
- 日志追踪:自动记录测试消息流向
4.应用功能测试案例
1. 应用管理测试集
TEST(DABHandler, ApplicationManagement) {
// 基础功能测试
onTopicTest("applications/list", "{}"); // 空参数查询
// 典型场景测试
onTopicTest("applications/launch",
R"({"appId":"YouTube"})"); // 标准应用启动
// 带参数启动测试
onTopicTest("applications/launch",
R"({
"appId": "Netflix",
"parameters": [
"-KEY",
"https%3A%2F%2Fwww.example.com%2F",
"-STANDALONE_PARAM"
]
})");
// 状态管理测试
onTopicTest("applications/get-state",
R"({"appId":"YouTube"})");
// 退出机制测试
onTopicTest("applications/exit",
R"({"appId":"YouTube"})"); // 常规退出
onTopicTest("applications/exit",
R"({"appId":"YouTube","background":true})"); // 后台退出
}
DAB实现中用到的主要设计模式的更多相关文章
- spring中用到了哪些设计模式
spring中用到了哪些设计模式?(顺丰) spring中常用的设计模式达到九种,我们举例说明: 第一种:简单工厂 又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种G ...
- Spring中用到了哪些设计模式?
谈谈Spring中都用到了哪些设计模式? JDK 中用到了那些设计模式?Spring 中用到了那些设计模式?这两个问题,在面试中比较常见.我在网上搜索了一下关于 Spring 中设计模式的讲解几乎都是 ...
- spring框架中用到了哪些设计模式
1.代理模式:在AOP和remoting中被用的比较多 2.单例模式:在spring配置文件中定义的bean默认为单例模式 3.模板方法模式:解决代码重复问题 4.前端控制器模式:spring提供了D ...
- HMI与设计模式
设计模式是做一个好的架构的一个基础.那么设计模式具体的概念是啥呢?百度百科曰:设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是 ...
- Head First设计模式——策略设计模式
策略设计模式 说在前面的话 入软件一年啦,平心而论,总算不限于只会钻研些基础的语言语法了,数据结构和算法也恶补的差不多了.所以~趁着现在一边实习一边啃<Head First设计模式>的功夫 ...
- 常见设计模式 (python代码实现)
1.创建型模式 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对 ...
- Java设计模式—单例设计模式(Singleton Pattern)全然解析
转载请注明出处:http://blog.csdn.net/dmk877/article/details/50311791 相信大家都知道设计模式,听的最多的也应该是单例设计模式,这种模式也是在开发中用 ...
- 高强度学习训练第十六天总结: Spring框架中的设计模式
仔细想了想..没必要重复造轮子. 每天复习啥了就直接CTRL CV了 https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/system-de ...
- 面试官:“谈谈Spring中都用到了那些设计模式?”。
我自己总结的Java学习的系统知识点以及面试问题,已经开源,目前已经 41k+ Star.会一直完善下去,欢迎建议和指导,同时也欢迎Star: https://github.com/Snailclim ...
- Spring中都用到了哪些设计模式
JDK 中用到了那些设计模式?Spring 中用到了那些设计模式?这两个问题,在面试中比较常见.我在网上搜索了一下关于 Spring 中设计模式的讲解几乎都是千篇一律,而且大部分都年代久远.所以,花了 ...
随机推荐
- 鸿蒙NEXT开发案例:随机数生成
[引言] 本项目是一个简单的随机数生成器应用,用户可以通过设置随机数的范围和个数,并选择是否允许生成重复的随机数,来生成所需的随机数列表.生成的结果可以通过点击"复制"按钮复制到剪 ...
- 【Spring】IOC核心源码学习(二):容器初始化过程
接上文 啃啃老菜: Spring IOC核心源码学习(一) ,本文将以 ClassPathXmlApplicationContext 这个容器的实现作为基础,学习容器的初始化过程. ClassPath ...
- JDK7新特性之G1 GC
Garbage-first garbage collector,简称G1 GC,是最终将用于代替Concurrent Mark-Sweep garbage collector(CMS GC)的新一代垃 ...
- nginx之日志切割
方便查看nginx日志, 平常会将nginx日志进行每日切割处理. 这里介绍 平常比较常用的两种方式 1. logrotate 在linux上logrotate是一个日志文件管理工具.用于分割日志文件 ...
- Codeforces Round 832 (Div2)
Swap Game Alice 和 Bob 两个人在玩游戏. 有一个长度为 \(n\) 的序列 \(a\),Alice 和 Bob 两人轮流完成一个操作,Alice 先开始. 每个人可以将数列的第一个 ...
- 负载均衡-一致性Hash算法
1. Hash算法 哈希(Hash)也称为散列,把任意长度的输入,通过散列算法变换成固定长度的输出,该输出就是散列值.哈希值(hashCode).(来自:百度百科) 在现实中,设计者常常将散列值作为索 ...
- 服务迁移之《mysql数据同步问题》
我们大概是从2022年十月份开始进行拆分的.面对一百多个服务的时候,真的是无从下手,然后公司突然空降了一个从阿里出来的架构师,然后就带着我们大刀阔斧的整体迁移. 先是服务器购买阿里云的,然后从几个核心 ...
- 使用TOPIAM 轻松搞定「Wiki.js」单点登录
本文将介绍 TOPIAM 与 Wiki 集成步骤详细指南. 应用简介 Wiki.js 是一款高度可定制且现代化的开源 Wiki 系统,专为团队知识管理和文档协作设计,具有强大的扩展性和跨平台支持能力. ...
- Redis应用—9.简单应用汇总
大纲 1.基于Redis实现的简单缓存机制(String数据结构) 2.实现一个最简单的分布式锁(String数据结构) 3.博客网站的文章发布与查看(String数据结构) 4.博客字数统计与文章预 ...
- Qt开源作品39-日志输出增强版V2022
一.前言 之前已经开源过基础版本,近期根据客户需求和自己的项目需求,提炼出通用需求部分,对整个日志重定向输出类重新规划和重写代码. 用Qt这个一站式超大型GUI超市做开发已经十二年了,陆陆续续开发过至 ...