日常工作中的设计:解耦和封装
时间: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参与,协作链变短了,开发效率变高,出问题的几率变小,出了问题也比较好定位。
- phalcon-入门篇5(请求与返回)
- phalcon-入门篇2(HelloWord与PhalconTools)
- 数据库中间件 Sharding-JDBC 源码分析 —— SQL 解析(一)之语法解析
- phalcon-入门篇4(log日志和session缓存)
- zephir-(5)类型
- zephir-(10)内置函数
- zephir-(9)类和对象2
- 深度学习中的动手实践:在CIFAR-10上进行图像分类
- 数据库中间件 MyCAT源码分析 —— XA分布式事务
- [喵咪Golang(1)]Go语言开篇
- phalcon-进阶篇2(拦截器)
- 【死磕Java并发】—–深入分析synchronized的实现原理
- phalcon-进阶篇1(过滤与清理)
- phalcon-入门篇9(view层基础使用)
- 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 数组属性和方法
- RTSP/GB28181/HIKSDK/Ehome协议视频融合平台EasyCVR编译C++报参见“XXX”的声明错误
- 详解 Linux 常用目录的作用
- CentOS6环境下搭建路由器的方法
- centos7下NFS使用与配置的步骤
- 基于DOM4J的XML文件解析类
- Win7安装和配置Apache2.4服务器的详细方法
- shiro会话管理示例代码
- Windows Apache2.4 VC9(ApacheHaus)详细安装配置教程
- 在centos 7中安装配置k8s集群的步骤详解
- Centos7.2 编译安装方式搭建 phpMyAdmin
- CentOS 6.5 web服务器apache的安装与基本设置
- Linux本机与服务器文件互传及Linux服务器文件上传下载命令写法
- linux利用read命令获取变量中的值
- 解决Centos7 安装腾达U12无线网卡驱动问题
- CentOS 6.5上编译安装Apache服务器的方法(最小化安装)