日常工作中的设计:解耦和封装
时间:2022-07-22
本文章向大家介绍日常工作中的设计:解耦和封装,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
本文介绍日常工作中模块间解耦,并抽象封装的一个例子。
一、问题提出
在一个嵌入式设备中,视频相关业务流程如下,DSP采集编码后,生成H264数据,然后对H264数据分别进行MP4、RTP、PS封装,封装后形成的数据进入对应的缓存队列。缓存队列是DSP和APP共享的,DSP写入,APP读取。
业务层(APP层)的录像模块(包括循环录像、事件录像等)从mp4数据包缓存队列
中读取数据进行存储,实时预览模块从RTP数据包缓存队列
中读取数据发送给客户端,平台接入模块从PS数据包缓存队列
中读取数据发送给平台。
我们先停下来想想,这种业务流程存在哪些问题?
- 录像存储是设备的主动行为,所以开机就要进行MP4封装,这个没问题;但是,实时预览和平台接入都是被动行为,RTP、PS封装是一直工作还是有任务的时候再工作?
- 如果一直工作,很多时候是在做无用功,白白浪费了资源;
- 如果外界触发的时候再工作,需要在APP和DSP之间增加控制指令,增加了交互的复杂性。
- 如果业务扩展,需要增加一个视频流类型怎么办?比如,对接一个新的客户端,视频流是TS流,需要修改以下几点:
- DSP层增加一个H264转TS的视频封装模块
- 增加一个TS流的共享缓存队列
- APP层增加TS业务处理流程
- 多个缓存队列,对内存资源是个挑战
- 录像、预览、平台接入等业务模块都是直接操作缓存队列,如果缓存队列的实现机制发生变化,缓存队列的所有使用者都需要修改。
- 我们不妨从团队分工协作的角度考虑一下(一般情况下DSP和APP是不同的团队),录像、预览、平台接入这些业务功能和DSP有关系吗?好像没有。那这些码流封装逻辑放在DSP会带来其他的好处吗,比如性能提升等?好像也没有。这样做只会导致业务的协作链特别长,带来的问题就是开发效率低,容易出问题,出了问题比较难定位。
二、优化方案
下图是优化后的流程图,变更点如下(绿色方框中的为主要变更内容):
- MP4、RTP、PS等码流封装模块从DSP层上移到APP层
- DSP和APP之间只有一个共享的
H264数据缓存队列
- 抽象出一个
帧读取器对象
,APP层的录像、预览、平台接入等模块不再直接操作缓存队列,而是通过帧读取器获取帧数据。
那么,这样做的好处在哪里?
- MP4封装、RTP封装、PS封装等任务由业务层按需启停,现在控制方便
- 如果业务扩展,DSP层不需要参与,只需要APP层修改以下几点:
- APP层增加一个H264转TS的视频封装模块
- APP层增加TS业务处理流程
- DSP和APP之间只有一个共享缓存队列,节省了内存资源
-
帧读取器对象
封装了缓存队列
的操作流程,如果缓存队列的实现机制变更,只需修改帧读取器对象即可。(这里类似设计模式中的策略模式) - 从团队分工协作的角度考虑:
- DSP只负责出H264数据流,APP层负责业务的多样性,二者都更加聚焦;
- 类似业务扩展不再需要DSP参与,协作链变短了,开发效率变高,出问题的几率变小,出了问题也比较好定位。
- 这或许是对小白最友好的python入门了吧——15,嵌套
- C#新功能--命名参数与可选参数
- 这或许是对小白最友好的python入门了吧——14,遍历字典
- C#新功能--命名参数
- Tomcat 安全配置与性能优化
- 【机器学习】伪标签(Pseudo-Labelling)的介绍:一种半监督机器学习技术
- 这或许是对小白最友好的python入门了吧——13,字典初识
- PHP 安全与性能
- 混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该...
- Linux 系统与数据库安全
- 这或许是对小白最友好的python入门了吧——12,列表深入体验
- 初识SqlLite ---.net连接数据库
- 【实践操作】:六步教你如何用开源框架Tensorflow对象检测API构建一个玩具检测器
- 这或许是对小白最友好的python入门了吧——11,if语句初体验
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Presto系列 | Presto基本介绍
- 如何在腾讯云中使用ExternalName类型的Service
- 一天一大 leet (990. 等式方程的可满足性)
- 一天一大 leet(有序矩阵中第 K 小的元素)难度:中等-Day20200702
- 一天一大 leet (126. 单词接龙 II)
- BigData--Yarn资源调度器
- 一天一大 leet(最长有效括号)难度:困难-Day20200704
- BigData--Zookeeper介绍和使用
- 一天一大 leet(通配符匹配)难度:困难-Day20200705
- 日志框架,选择Logback Or Log4j2?
- django-rest-framework配置json web token进行接口的认证
- spring中的SpEL表达式
- 京喜小程序首页无障碍优化实践
- 几种排序算法
- 一天一大 leet(转变数组后最接近目标值的数组和)难度:中等 DAY-14