架构技能(六):软件设计(下)

我们知道,软件设计包括软件的整体架构设计和模块的详细设计。

在上一篇文章(见 《架构技能(五):软件设计(上)》)谈了软件的整体架构设计,今天聊一下模块的详细设计。

模块的详细设计,重点体现在需要设计几个具有明确职责的角色,以及角色之间应该设计成什么样的关系,这里的角色一般是一个很大的类;然后对每一个角色继续分析需要设计几个类来实现角色职责,以及类与类之间应该设计成什么样的关系。

模块的详细设计,应该像架构设计一样,由高到低,逐层进行。

在之前的文章(见《架构技能(一):软件架构》)中,分析过软件架构,见下图。

软件架构是指软件系统的顶层结构,包含具有明确职责的角色,这些角色通过相互协作使软件系统提供业务能力。

一个模块应该设计成几个类,取决于业务场景;但是类与类之间的关系是固定的模式,从原子化不可再分的角度看,共包括六类关系:依赖、关联、聚合、组合、继承、实现;“继承” 和 “实现” 更多是为了多态特性的实现需要,在基础框架中应用普遍,在业务系统中以前四种类关系应用为主。

依赖

依赖方与被依赖方是 “使用” 关系,从代码上看,被依赖方对象往往出现在依赖方对象的方法内部。比如:依赖方是 Person,被依赖方是 Bus,人 “使用” 公共汽车,见下图。

关联

关联方与被关联方是 “拥有” 关系,从代码上看,被关联方对象往往出现在关联方对象的成员变量上。比如:关联方是 Person,被关联方是 Phone,人 “拥有” 手机,见下图。

聚合

聚合方与被聚合方是整体与个体之间的关联关系,整体 “拥有” 个体,个体 “聚合” 成整体。从代码上看,被聚合方对象出现在关联方对象的成员变量上。比如:聚合方是 Company,被聚合方是 Staff,公司 “拥有” 员工,员工 “聚合” 成公司,见下图。

组合

组合方与被组合方仍是整体与个体之间的关联关系,整体 “拥有” 个体,个体 “组合” 成整体,与聚合关系不同的是,被组合方不能独立存在。从代码上看,被组合方对象出现在组合对象的成员变量上,且在组合对象内部进行初始化。比如:组合方是 Computer,被组合方是 Cpu,计算机 “拥有” CPU,CPU “组合” 成了计算机,且 CPU 离开计算机不能独立存在,见下图。

总结一下在软件模块详细设计中,类与类之间最常用的四种关系:

  • 依赖的核心是 “使用”,两个对象在同一层次上;

  • 关联的核心是 “拥有”,两个对象在同一层次上;

  • 聚合的核心是 整体与个体之间的 “拥有” 与 “聚合”,个体离开整体后对象的生命周期可以继续;

  • 组合的核心是 整体与个体之间的 “拥有” 与 “组合”,个体离开整体后对象的生命周期结束。

理解这四类对象关系,并烂熟于心,那就可以对软件业务系统模块进行详细设计了。

这里,我们以 基于时间轮的 HTTP 长轮询获取消息为例,描述软件模块详细设计的过程。

先简述一下 HTTP 长轮询,见下图。

  • http 客户端向 http 服务端发起 http 请求;

  • http 服务端 hold 住该请求,不会立刻返回 http 响应;

  • http 服务端只有满足两个条件中的任何一个才会返回 http 响应: 要么超过一定时间(超时),要么产生了属于客户端的消息

  • http 客户端收到响应后,再次发起 http 请求,重复上述过程。

在这个场景里, http 服务端应该如何设计呢?

分析上述时序图,可以很容易得出:http 服务端需要包含三个角色,即 http服务、消息模块和时间轮模块,三个角色之间的关系,见下图。

  • http 客户端向 http 服务端发起 http 请求;

  • http 服务端 hold 住该请求,不会立刻返回 http 响应;

  • http 服务端只有满足两个条件中的任何一个才会返回 http 响应: 要么超过一定时间(超时),要么产生了属于客户端的消息

  • http 客户端收到响应后,再次发起 http 请求,重复上述过程。

在这个场景里, http 服务端应该如何设计呢?

分析上述时序图,可以很容易得出:http 服务端需要包含三个角色,即 http服务、消息模块和时间轮模块,三个角色之间的关系,见下图。

  • 时间轮对于 http 服务来说是一个工具,http 服务使用时间轮这个工具进行管道的注册,所以 HttpService 类 “依赖” 于 Wheel 类;

  • 消息模块产生新的消息时,根据客户端的 uid 从时间轮中获取客户端的管道,所以 MsgManager 类 “依赖“ 于 Wheel 类;

  • 消息模块与 http 服务之间没有直接关系,消息模块只是通过管道对象将消息传输给 http 服务而已。

明确了第一层的类关系,就可以对第二层的类关系进行展开分析和设计了。http 服务与消息模块留给大家进行设计,我们看时间轮模块如何设计。

对类内部的设计,需要从类对外提供的能力来入手分析。

通过对 http 服务、消息模块、时间轮模块三个角色之间的关系分析,我们知道时间轮对外提供了三项能力:

  • 对客户端管道对象的注册;

  • 对客户端超时信息的发送;

  • 根据客户端 uid 获取用户的管道。

注册客户端管道时,需要包括用户 uid、用户管道、注册时的时间轮刻度等信息;对客户端超时信息发送时,需要根据时间轮刻度找到用户管道;而获取用户管道时,需要根据客户端 uid 获取。所以,为了方便查询,用户 uid 与时间轮时间应该是一个双向映射的关系;同时,便于维护,将用户管道与时间轮时间封装成用户信息对象。

这里的管道对象,在不同的语言中可以采用不同的实现方式,比如 Go 语言中可以采用 chan ,Java 语言中可以采用队列。时间轮模块内部原理,在之前的文章(见《单体架构 IM 系统之长轮询方案设计》)中有详细描述,见下图。

时间轮模块类 Wheel 内部应包含三个类: 时间盘(TimeDisk)、用户信息映射(UserInfoMap)、时间轮刻度映射(TimeUserMap),这几个类之间的关系,见下图:

        

  • 时间轮对象 “拥有” 时间盘、用户信息映射和时间轮刻度映射三个对象,这三个对象组合成了时间轮对象,所以 Wheel 与 TimeDisk、UserInfoMap、TimeUserMap 是组合关系,离开了 Wheel,这三个对象毫无意义;

  • 时间盘 TimeDisk 对象,提供时间指针每秒走一格的能力;下一格的时间刻度所映射的所有客户端列表就是超时的客户端;

  • 用户信息映射 UserInfoMap 对象提供用户 uid 对用户信息对象的映射能力;

  • 时间轮刻度映射 TimeUserMap 对象提供时间轮时间刻度对用户 uid 列表的映射能力;

  • TimeDisk、UserInfoMap、TimeUserMap 三个对象之间没有任何关系。

我们继续对 UserInfoMap 设计第三层类关系,TimeDisk 和 TimeUserMap 留给大家分析和设计,见下图。

  • UserInfoMap “拥有” UserInfo,UserInfo “聚合” 成了 UserInfoMap,UserInfoMap 和 UserInfo 是聚合关系;

  • UserInfo 中封装了管道 UserChan 对象,UserInfo “拥有” UserChan 对象,两者是关联关系。

对业务模块的类关系,通常设计到第三层,整个类关系脉络应该就非常清晰了;http 服务端,将上述三层类关系进行整合,见下图。

在这个简单的整体类关系图中,依赖、关联、聚合、组合四种类关系全部进行了应用。明确了整个模块中关键类之间的关系后,剩下的就是对方法逻辑的编写了,这对于初级程序员来说就不是个事了!

最后,总结文中关键:

  1. 模块的详细设计,重点体现在需要设计几个具有明确职责的角色(类),以及角色(类)之间应该设计成什么样的关系;

  2. 模块的详细设计,应该像架构设计一样,由高到低,逐层进行;

  3. 类之间包括六类关系:依赖、关联、聚合、组合、继承和实现,在业务系统中以前四类为主:

    (1)依赖的核心是 “使用”;

    (2)关联的核心是 “拥有”;

    (3)聚合的核心是 整体与个体之间的 “拥有” 与 “聚合”,个体离开整体后对象的生命周期可以继续;

    (4)组合的核心是 整体与个体之间的 “拥有” 与 “组合”,个体离开整体后对象的生命周期结束;

  4. 对类内部的设计,需要从类对外提供的能力来入手分析;

  5. 基于时间轮方案实现的 http 长轮询中,关键类之间的关系如下:

    (1)HttpService 依赖 Wheel;

    (2)MsgManager 依赖 Wheel;

    (3)Wheel 组合 TimeDisk;

    (4)Wheel 组合 UserInfoMap;

    (5)Wheel 组合 TimeUserMap;

    (6)UserInfoMap 聚合 UserInfo;

    (7)UserInfo 关联 UserChan。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/69844.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

杨波 简单逻辑学:理性思考、清晰表达并解决问题 - 读书笔记

目录 简单逻辑学:理性思考、清晰表达并解决问题PART 01 如何成为半秒看透问题本质的人半秒看透问题本质,靠的是逻辑思考力我们一直在说的“本质”到底是什么解决问题的能力,决定了个人的价值玩游戏讲规则,逻辑思考也得遵循规律真正…

CSS 图像、媒体和表单元素的样式化指南

CSS 图像、媒体和表单元素的样式化指南 1. 替换元素:图像和视频1.1 调整图像大小示例代码:调整图像大小 1.2 使用 object-fit 控制图像显示示例代码:使用 object-fit 2. 布局中的替换元素示例代码:Grid 布局中的图像 3. 表单元素的…

基于微信小程序的实习记录系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…

B-树:解锁大数据存储和与快速存储的密码

在我们学习数据结构的过程中,我们会学习到二叉搜索树、二叉平衡树、红黑树。 这些无一例外,是以一个二叉树展开的,那么对于我们寻找其中存在树中的数据,这个也是一个不错的方法。 但是,如若是遇到了非常大的数据容量…

【实战篇章】深入探讨:服务器如何响应前端请求及后端如何查看前端提交的数据

文章目录 深入探讨:服务器如何响应前端请求及后端如何查看前端提交的数据一、服务器如何响应前端请求HTTP 请求生命周期全解析1.前端发起 HTTP 请求(关键细节强化版)2. 服务器接收请求(深度优化版) 二、后端如何查看前…

【视频+图文详解】HTML基础4-html标签的基本使用

图文教程 html标签的基本使用 无序列表 作用&#xff1a;定义一个没有顺序的列表结构 由两个标签组成&#xff1a;<ul>以及<li>&#xff08;两个标签都属于容器级标签&#xff0c;其中ul只能嵌套li标签&#xff0c;但li标签能嵌套任何标签&#xff0c;甚至ul标…

【Elasticsearch】 索引模板 ignore_missing_component_templates

解释 ignore_missing_component_templates 配置 在Elasticsearch中&#xff0c;ignore_missing_component_templates 是一个配置选项&#xff0c;用于处理索引模板中引用的组件模板可能不存在的情况。当您创建一个索引模板时&#xff0c;可以指定一个或多个组件模板&#xff0…

网络工程师 (8)存储管理

一、页式存储基本原理 &#xff08;一&#xff09;内存划分 页式存储首先将内存物理空间划分成大小相等的存储块&#xff0c;这些块通常被称为“页帧”或“物理页”。每个页帧的大小是固定的&#xff0c;例如常见的页帧大小有4KB、8KB等&#xff0c;这个大小由操作系统决定。同…

LabVIEW无人机航线控制系统

介绍了一种无人机航线控制系统&#xff0c;该系统利用LabVIEW软件与MPU6050九轴传感器相结合&#xff0c;实现无人机飞行高度、速度、俯仰角和滚动角的实时监控。系统通过虚拟仪器技术&#xff0c;有效实现了数据的采集、处理及回放&#xff0c;极大提高了无人机航线的控制精度…

搜索引擎快速收录:关键词布局的艺术

本文来自&#xff1a;百万收录网 原文链接&#xff1a;https://www.baiwanshoulu.com/21.html 搜索引擎快速收录中的关键词布局&#xff0c;是一项既精细又富有策略性的工作。以下是对关键词布局艺术的详细阐述&#xff1a; 一、关键词布局的重要性 关键词布局影响着后期页面…

实现B-树

一、概述 1.历史 B树&#xff08;B-Tree&#xff09;结构是一种高效存储和查询数据的方法&#xff0c;它的历史可以追溯到1970年代早期。B树的发明人Rudolf Bayer和Edward M. McCreight分别发表了一篇论文介绍了B树。这篇论文是1972年发表于《ACM Transactions on Database S…

新一代搜索引擎,是 ES 的15倍?

Manticore Search介绍 Manticore Search 是一个使用 C 开发的高性能搜索引擎&#xff0c;创建于 2017 年&#xff0c;其前身是 Sphinx Search 。Manticore Search 充分利用了 Sphinx&#xff0c;显着改进了它的功能&#xff0c;修复了数百个错误&#xff0c;几乎完全重写了代码…

iperf 测 TCP 和 UDP 网络吞吐量

注&#xff1a;本文为 “iperf 测网络吞吐量” 相关文章合辑。 未整理去重。 使用 iperf3 监测网络吞吐量 Tom 王 2019-12-21 22:23:52 一 iperf3 介绍 (1.1) iperf3 是一个网络带宽测试工具&#xff0c;iperf3 可以擦拭 TCP 和 UDP 带宽质量。iperf3 可以测量最大 TCP 带宽…

神经网络的数据流动过程(张量的转换和输出)

文章目录 1、文本从输入到输出&#xff0c;经历了什么&#xff1f;2、数据流动过程是张量&#xff0c;如何知道张量表达的文本内容&#xff1f;3、词转为张量、张量转为词是唯一的吗&#xff1f;为什么&#xff1f;4、如何保证词张量的质量和合理性5、总结 &#x1f343;作者介…

MediaPipe与YOLO已训练模型实现可视化人脸和手势关键点检测

项目首页 - ZiTai_YOLOV11:基于前沿的 MediaPipe 技术与先进的 YOLOv11 预测试模型&#xff0c;精心打造一款强大的实时检测应用。该应用无缝连接摄像头&#xff0c;精准捕捉画面&#xff0c;能即时实现人脸检测、手势识别以及骨骼关键点检测&#xff0c;将检测结果实时、直观地…

JAVA篇12 —— 泛型的使用

​ 欢迎来到我的主页&#xff1a;【Echo-Nie】 本篇文章收录于专栏【JAVA学习】 如果这篇文章对你有帮助&#xff0c;希望点赞收藏加关注啦~ 1 泛型介绍 先对集合进行说明&#xff0c;不能对加入到集合中的元素类型进行约束&#xff08;不安全&#xff09;。遍历的时候需要…

JavaScript 数据类型

基本概念 什么是数据类型 JavaScript是一种 灵活的动态类型语言 &#xff0c;其数据类型构成了程序的基础构建块。它主要包括两类数据类型&#xff1a; 原始数据类型 &#xff1a;包括String、Number、Boolean、Undefined、Null和Symbol。 复杂数据类型 &#xff1a;以Object…

被裁与人生的意义--春节随想

还有两个月就要被迫离开工作了十多年的公司了&#xff0c;不过有幸安安稳稳的过了一个春节&#xff0c;很知足! 我是最后一批要离开的&#xff0c;一百多号同事都没“活到”蛇年。看着一批批仁人志士被“秋后斩首”&#xff0c;马上轮到我们十来个&#xff0c;个中滋味很难言清…

【multi-agent-system】ubuntu24.04 安装uv python包管理器及安装依赖

uv包管理器是跨平台的 参考sudo apt-get update sudo apt-get install -y build-essential我的开发环境是ubuntu24.04 (base) root@k8s-master-pfsrv:/home/zhangbin/perfwork/01_ai/08_multi-agent-system# uv venv 找不到命令 “uv”,但可以通过以下软件

Redis代金卷(优惠卷)秒杀案例-多应用版

Redis代金卷(优惠卷)秒杀案例-单应用版-CSDN博客 上面这种方案,在多应用时候会出现问题,原因是你通过用户ID加锁 但是在多应用情况下,会出现两个应用的用户都有机会进去 让多个JVM使用同一把锁 这样就需要使用分布式锁 每个JVM都会有一个锁监视器,多个JVM就会有多个锁监视器…