实际开发中的模块化开发 - 应用到直播间
实际开发中的模块化开发 - 模块管理(以直播间为例)-CSDN博客
引言
在前面的两篇博客中,我们已经介绍了直播模块的简单结构,创建了模块管理器和模块抽象基类,并且通过模块化实现了两个小业务功能模块。接下来,我们构建了一个用于模块间通讯的消息总线,这个消息总线可以在模块间进行通讯和数据传递。不过,消息总线还没有实际应用到我们的项目中。本篇博客中,我们将模块管理和消息总线整合到一起,并将它们应用到直播间内。
准备工作

直播间模块基类
在使用它们之前我们仍然有许多准备工作需要完成,首先我们需要创建一个专属于直播间的模块抽象基类,它并不会单独使用,但是会为其它子模块提供一些直播间内的信息和方法。
import UIKit
import PHRoomModuleManagerclass PHRoomModule: PHModule {/// 直播间视图控制器var roomViewController:PHRoomViewController? {if let roomViewController = self.controlCenter?.ownerController as? PHRoomViewController {return roomViewController}return nil}/// 直播间视图var roomView:UIView? {return self.roomViewController?.view}/// 是否是主播var isAnchor:Bool {return self.roomViewController?.isAnchor ?? false}/// 主播信息var anchorInfo:PHAnchorInfo? {return self.roomViewController?.anchorInfo}/// 直播间信息var roomInfo:PHRoomInfo? {return self.roomViewController?.roomInfo}
}
模块构建器
在上面的截图中可以看到我们还创建了一个三个模块构建器,分别负责创建公共模块,主播专属模块和观众专属模块。
公共模块:我们会将所有主播端和观众端都包含的功能模块在这里面创建,比如用户卡片。
import UIKit
import PHRoomModuleManagerclass PHRoomCommonModuleBuilder: NSObject {/// 模块列表private(set) var modules: [PHModuleModel] = []/// 创建所有模块func buildModules() {}/// 添加模块/// - Parameters:/// - moduleIdentifier: 模块标识/// - moduleIndex: 模块序号/// - moduleDescription: 模块描述/// - moduleClassString: 模块类字符串/// - receiverMessage: 模块接收的消息func addModule(moduleIdentifier: String, moduleIndex: Int = 0, moduleDescription: String, moduleClassString: String,receiverMessage: [String] = []) {let moduleModel = PHModuleModel()moduleModel.moduleIdentifier = moduleIdentifiermoduleModel.moduleIndex = moduleIndexmoduleModel.moduleDescription = moduleDescriptionmoduleModel.moduleClassString = moduleClassStringmoduleModel.receiverMessage = receiverMessagemodules.append(moduleModel)}}
主播模块:专属与主播的业务功能将会在这里面创建,比如美颜模块。
import UIKitclass PHRoomSPModuleBuilder: PHRoomCommonModuleBuilder {/// 创建所有模块override func buildModules() {super.buildModules()}}
观众模块:观众的业务功能模块将会在这里面创建,比如礼物面板模块。
import UIKitclass PHRoomLPModuleBuilder: PHRoomCommonModuleBuilder {/// 创建所有模块override func buildModules() {super.buildModules()}}
模块和消息标识
另外还有两个文件主要负责定义模块标识字符和消息标识字符串。
创建控制中台
接下里我们把重点转移到直播间的视图控制器内,开始创建控制中台来整合模块管理和消息总线。
import UIKit
import PHRoomModuleManagerclass PHRoomViewController: UIViewController {/// 模块化中台private var controlCenter: PHRoomControlCenter!/// 是否是主播var isAnchor: Bool = false/// 主播信息private(set) var anchorInfo: PHAnchorInfo?/// 直播间信息private(set) var roomInfo: PHRoomInfo?override func viewDidLoad() {super.viewDidLoad()self.view.backgroundColor = .whitesetupModuleManager()// 其它准备工作// ... 请求主播信息// ... 请求直播间信息controlCenter.moduleDidLoad()}/// 初始化模块管理器private func setupModuleManager() {let builder: PHRoomCommonModuleBuilderif isAnchor {builder = PHRoomSPModuleBuilder()} else {builder = PHRoomLPModuleBuilder()}builder.buildModules()controlCenter = PHRoomControlCenter(ownerController: self, modules:builder.modules)}deinit {controlCenter.unloadModules()print("房间控制器销")}}
创建模块

在这个直播间场景中我们创建了三个模块,主播信息模块,直播信息模块和用户公告板模块。
其中主播信息模块比较独立,而直播信息和用户公共版之间将会涉及到消息通讯,下面让我们来看一下如何构建模块的吧。
由于三个都属于公共模块,所以他们的创建都会放在PHRoomCommonModuleBuilder下,代码如下:
/// 创建所有模块func buildModules() {// 房间间信息模块addModule(moduleIdentifier: PHRoomModuleIdentifier, moduleIndex: 0, moduleDescription: "直播间信息模块", moduleClassString: "PHCPRoomInfoModule")// 直播信息模块addModule(moduleIdentifier: PHCPLiveInfoModuleIdentifier, moduleIndex: 1, moduleDescription: "直播信息模块", moduleClassString: "PHCPLiveInfoModule")// 公告板addModule(moduleIdentifier: PHCPAnnouncementModuleIdentifier, moduleIndex: 2, moduleDescription: "公告板", moduleClassString: "PHCPAnnouncementModule",receiverMessage: [kAnnouncementButtonClickedMessage])}
其中公告板模块需要接收一个标识符为kAnnouncementButtonClickedMessage的消息,也就是点击公告板按钮的消息。
模块内的具体UI代码,在这里就一一介绍了,稍后项目会上传到资源中。
消息通讯
发送消息:
在直播间信息的UI中有一个公告板的按钮,我们实现它的点击事件并传递到房间信息模块中,在点击事件内发送我们定义好的消息,此消息不需要携带任何参数,所以数据我们可以不传。
/// 添加信息视图private func addAnchorVolumeView() {guard let roomView = self.roomView else { return }roomView.addSubview(anchorVolumeView)anchorVolumeView.layer.cornerRadius = 16.0anchorVolumeView.backgroundColor = UIColor.white.withAlphaComponent(0.5)anchorVolumeView.snp.makeConstraints { (make) inmake.leading.equalToSuperview().offset(16.0)make.trailing.equalToSuperview().offset(-16.0)make.top.equalToSuperview().offset(navigationBarHeight + 32.0)make.height.equalTo(126.0)}anchorVolumeView.bulletinAction = { [weak self] inself?.postMessage(messageIdentifier: kAnnouncementButtonClickedMessage, messageData: nil)}}
处理消息:
在公告板的模块内接收并处理消息,来决定公告板的显示和隐藏。
class PHCPAnnouncementModule: PHRoomModule {/// 公告板private var announcementView:SVAnnouncementView?override func receiveMessage(message: PHMessage) {if message.messageIdentifier == kAnnouncementButtonClickedMessage {if let animationView = self.announcementView {UIView.animate(withDuration: 0.25, animations: {animationView.alpha = 0}) { _ inanimationView.removeFromSuperview()self.announcementView = nil}} else {addAnnouncementView()}}}func addAnnouncementView() {self.announcementView = SVAnnouncementView()guard let roomView = self.roomView else { return }guard let announcementView = announcementView else { return }roomView.addSubview(announcementView)announcementView.snp.makeConstraints { make inmake.trailing.equalToSuperview().offset(-16.0)make.top.equalToSuperview().offset(navigationBarHeight + 32.0 + 40.0)}announcementView.renderUser()announcementView.alpha = 0UIView.animate(withDuration: 0.25) {self.announcementView?.alpha = 1}}
}
结语
博客到此为止,我们完整演示了如何在模块化开发中利用模块管理和消息总线来实现模块间的消息和数据传递。消息总线的引入显著减少了模块之间的依赖关系,使得在大多数情况下,我们无需从一个模块中直接访问另一个模块。
尽管目前的方法已经适用于大多数项目,但在处理复杂的直播间业务时,它依然显得过于简洁。目前的系统仅区分了主播和观众,尚未考虑房间类型的区分。此外,所有模块都是直接加载的,这可能会导致资源浪费。在模块化结构中,模块加载的顺序也是至关重要的,我们将在后续版本中进一步完善这些问题。
相关文章:
实际开发中的模块化开发 - 应用到直播间
实际开发中的模块化开发 - 模块管理(以直播间为例)-CSDN博客 引言 在前面的两篇博客中,我们已经介绍了直播模块的简单结构,创建了模块管理器和模块抽象基类,并且通过模块化实现了两个小业务功能模块。接下来…...
EmguCV学习笔记 VB.Net 第5章 图像变换
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访…...
【初阶数据结构】顺序表与链表的比较(附题)
目录 一、顺序表和链表的区别(其他链表存在缺陷,比较意义不大,这里用带头双向循环链表与顺序表进行比较) 1.1插入、扩容与随机访问 二、缓存利用率的比较 2.1前置知识 详解及补充知识(本文仅为比较顺序表及链表&am…...
git-20240822
目录 初始化仓库 Git init Git init project --bare 查看提交的记录 git log --prettyoneline 查看当前git远程库地址 git remote -v 查看详细提交记录 git log 撤出暂存区的文件 git reset HEAD file(.代表全部文件) 提交数据到远程仓库 git config --global push.…...
【时时三省】c语言例题----华为机试题< 数字颠倒>
目录 1,题目 描述 输入描述: 输出描述: 示例1 2,代码...
【前缀和算法】--- 一维和二维前缀和模板
Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏: 算法Journey 本文开始,博主开始讲解有关前缀和的算法,本篇博客我们先来了解一下有关前缀和的两个模板。 🏠 一维前缀和模板 &…...
有些信息注定会丢失
智能在分析问题、做出决策时,总是希望获取尽可能多的信息,以此更加准确地决策。然而,很遗憾的是,有一些信息注定会丢失,不可能获取完全的信息,而且即使能够获取,智能也不能完全利用。 这一点与…...
c#中Task.Run 和使用 Task 构造函数创建任务的区别
Task.Run 和使用 Task 构造函数创建任务是两种不同的方法,它们在某些方面有显著的区别: 启动方式: Task.Run 是一个静态方法,它立即启动一个任务并在后台执行指定的工作。它通常用于快速启动一个简单的后台任务。使用 Task 构造函数创建任务&…...
使用nginx做代理转发
需求1:通过监听服务器的80端口,将请求转发到另一台服务器的8070端口 打开nginx/nginx.conf文件 server {listen 80;server_name localhost;location /analys {proxy_pass http://10.xx.xx.xx:8070/;} }需求2:通过监听服务器的80端口&am…...
Java前端与后端交互:JSON与XML数据交换 - 掌握现代Web开发的核心技能
引言 随着互联网技术的不断进步,Web应用变得越来越复杂,从前端到后端的每一个环节都需要精心设计以保证良好的用户体验。在这个过程中,数据的传递扮演着至关重要的角色。无论是简单的表单提交还是复杂的API调用,都需要一种可靠的…...
网络攻击原理及过程
网络攻击原理表 攻击者 内容 攻击访问 攻击效果 攻击意图 黑客 挑战 间谍 用户命令 破坏信息 好奇 恐怖主义者 脚本或程序 本地访问 信息泄密 获取情报 公司职员 自治主体 远程访问 窃取服务 经济利益 职业犯罪分子 电磁泄露 拒绝服务 恐怖事…...
day30(8/16)——ansible
目录 一、回顾 1、mysql和python 1. mysql5.7 2. 可以使用pymysql非交互的管理mysql 2、mycat中间件 1. 独属于mysql主从的负载均衡策略 2.配置写主读从 3. 步骤 3.1 安装jdk 3.2 mycat 3.3 配置 3.4 启动和调试 二、运维自动化(ansible) 1、任务背…...
fastadmin 安装
环境要求,大家可以参考官方文档的,我这里使用的是phpstudy,很多已经集成了。 注意一点,PHP 版本:PHP 7.4 。 第二步:下载 下载地址:https://www.fastadmin.net/download.html 进入下载地址后…...
Unity动画模块 之 3D模型导入基础设置 Rig页签
本文仅作笔记学习和分享,不用做任何商业用途本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正 1.Rig页签 Rig 选项卡 - Unity 手册,rig是设置骨骼与替身系统的,工作流程如下 Avatar是什么…...
⭐️Python在Windows命令行(Command Prompt)运行Python脚本或交互式地执行Python代码详解
Python在Windows命令行(Command Prompt)运行Python脚本或交互式地执行Python代码详解 Python在Windows命令行(Command Prompt)运行Python脚本或交互式地执行Python代码详解一、安装Python二、运行Python脚本1. 打开命令行2. 导航到…...
Python | Leetcode Python题解之第355题设计推特
题目: 题解: class Twitter:class Node:def __init__(self):self.followee set()self.tweet list()def __init__(self):self.time 0self.recentMax 10self.tweetTime dict()self.user dict()def postTweet(self, userId: int, tweetId: int) ->…...
D. Beard Graph
https://codeforces.com/problemset/problem/165/D 主要是边转点 后面都是简单的线段树维护 我们维护ok标记,val值,黑(1),白(0) id.okl.ok&r.ok id.vall.valr.val 注意特判如果两个点一样是0,如果dfn[u]1>dfn[v]就不…...
使用预训练的 ONNX 格式的 YOLOv8n 模型进行目标检测,并在图像上绘制检测结果
目录 __init__方法: pre_process方法: run方法: filter_boxes方法: view_img方法: __init__方法: 初始化类的实例时,创建一个onnxruntime的推理会话,加载名为yolo…...
mac安装xmind
文章目录 介绍软件功能下载安装1.下载完成后打开downloads 双击进行安装2.将软件拖到应用程序中3.在启动台中搜索打开4.提示损坏问题解决5.执行完成关闭命令窗口6.打开成功,点击继续,跳过登录7.打开成功后,点击关于 小结 介绍 XMind 是一款流…...
MySQL分区表入门
MySQL数据库的分区表是一种将表数据分成逻辑上相关的部分并存储在不同的物理位置的技术。使用分区表可以提高查询性能、简化数据维护和提供更好的数据管理。 以下是MySQL中创建和使用分区表的一般步骤: 设计分区策略: 首先,需要确定如何将表…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...
【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...
海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》
近日,嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》,海云安高敏捷信创白盒(SCAP)成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天,网络安全已成为企业生存与发展的核心基石,为了解…...
从实验室到产业:IndexTTS 在六大核心场景的落地实践
一、内容创作:重构数字内容生产范式 在短视频创作领域,IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色,生成的 “各位吴彦祖们大家好” 语音相似度达 97%,单条视频播放量突破百万…...
麒麟系统使用-进行.NET开发
文章目录 前言一、搭建dotnet环境1.获取相关资源2.配置dotnet 二、使用dotnet三、其他说明总结 前言 麒麟系统的内核是基于linux的,如果需要进行.NET开发,则需要安装特定的应用。由于NET Framework 是仅适用于 Windows 版本的 .NET,所以要进…...
