前言
之所以开设“前人种树”专栏,是因为笔者十分推崇某位牛马前辈,当初刚入学对实验一筹莫展时偶然接触到这位前辈分享的材料,且不说对我有没有帮助,反正从那以后我经常看他分享的实验材料。慢慢地看多了之后才发现,原来这位前辈发材料的初衷可能没有我想的那么高尚,不是为了作为前人种树让后来人乘凉的,纯纯为了炫耀。为什么这么说呢?因为基本上他所有的公开分享的材料,都是要么缺斤少两,要么就在某个细节上把原来正确的改成错的。而他收费恰米的材料,都是完全正确可以直接拿来用的。
所以我呢,就把自己的实验材料也做个分享,不缺斤少两,更不故意把对的改成错的让后面的学弟们找半天,故意捉弄人嘛这不是?【楽】希望我这个种树的前人能对后人们有些许帮助,也希望各位是在弄懂我的东西后才去套用甚至自创。
说远了,回来说说这两门课程的实验吧:这两门课程可以分开做也可以合做一个更为复杂的大型的综合实验,分开做的话就是——软件体系结构仍然需要做分布式多车协作探索系统,但就不需要把软件工程的全套流程(从需求分析到测试)全做完,只需要编码实现功能,把这个系统做出来就够。至于软件工程则另外做一个简单点的如平时上课常讲的图书馆管理系统;合做综合实验就是——既要完成软件体系结构的系统设计和实现,同时又要把软件工程的全流程走一遍下来。前者成绩最多只能为良,后者可以冲优。
说回笔者的情况:笔者自己带了一个四人小组,起初选题时组员都不太积极争取,只想选择简单的分做项目。但为了冲优,笔者向组员许诺包揽工作,才得以顺利选择做两个课程公共的综合大实验“分布式多车协作探索系统”。这里要感谢组员们,虽然最后选择了与他们初衷违背的选题,但选题之后大家还是积极配合笔者工作,努力不给笔者添麻烦,主动提出帮助笔者做一些边边角角的琐事。感谢感谢,你们的态度让笔者感到无比欣慰,感到自己的所有付出都是值得的。
最后,附上体系架构设计思路讲解视频,小破站传送点
一、课程设计(综合实验)的目的与要求
软件体系结构是软件工程专业的专业必修课。软件体系结构是软件工程方法学的一个分支,开设本课程的目的是使学生在了解了软件工程基础原理、方法、过程的基础上进一步掌握软件结构设计的基本理论和方法,培养设计软件结构的基本能力。本课程的基本内容包括软件体系结构的基本概念、发展现状、软件体系结构风格、传统的软件体系结构、现代软件体系结构等。
本课程实验的目标是培养学生的基础编程能力,其培养目标是程序员;软件工程课程使学生上升到软件系统的认识,其培养目标是软件工程师。本课程教学内容属于软件工程的概要设计阶段的方法学,其培养目标是软件架构师。
二、设计(实验)正文
1.项目简介
1.1项目背景、意义
为了应对我国广袤而复杂的自然地理环境,我们计划设计一个智能探索系统,以紧急救援和地图搜索为应用背景,简要实现小车的地图探索功能。
1.2系统简要描述、主要功能
用户(超管、普通管理员、普通用户)进行注册后可以登录使用该系统。系统支持多小车同时探索,并且根据模拟实情,支持中途添加小车和导航器来进行地图探索,既可以使用现有的障碍物地图,也可以随机生成地图或是自定义地图设置,并对小车探索路径和时间等信息进行实时显示,最终实现地图的完全探索后(也可提前结束探索),可以进行路径回放和数据分析。
a.小车的智能路径规划功能。通过分析地图数据,小车将能够自主规划最佳路径,避开障碍物并克服复杂地形。小车将能够实时显示其当前位置和走过的路径,从而提供精确的导航和定位服务。
b.支持多用户多小车同时参与地图探索任务。不同的用户可以远程控制多辆小车,协同 完成探险任务。他们可以共享地图数据和探索成果,相互协作并交流,提高整个团队的效率和成果。
c.地图动态更新功能。由于地理环境的不断变化,如自然灾害、地壳运动等,地图需要及时更新以保持准确性。使用者可以随时更新地图数据,并实时传输给小车,以确保探索活动的 可靠性和实用性。
d.路径回放功能。使用者可以回放小车已经探索过的路径,观察和分析探险过程,帮助他们更好地理解所探索区域的特征和变化。
2. 可行性分析报告
2.1 技术可行性分析
项目运用java语言,基于IDEA、Redis、activeMQ、SQL Server 2012实现,当前所运用技术成熟完备,支持该项目完成既定目标。
2.2 经济可行性分析
在本项目的基建投资方面,可以利用现有设备,无需额外投资新的硬件设备。
相关费用主要包括软件设计费、开发费用和软件维护费。这些费用可以通过合理控制和规划,确保项目的经济可行性。
2.3 法律可行性分析
本系统基于学长原创开发的项目复现,并且进行了重构二创,已取得学长同意,在法律方面不会存在侵犯专利权、侵犯版权等问题,完全按照合同规定的责任履行。
2.4 用户使用可行性分析
项目遵循交互界面的黄金设计三原则,注重简洁设计,页面数量不多,各功能指示清晰明了。在研发过程中,充分考虑了用户的工作流程和计算机操作水平,旨在提供更加人性化和直观的界面,以满足用户需求。系统的操作方式适用于用户所在的组织,用户能够轻松上手并使用该系统,而无需改变原有的操作习惯。
2.5 可供选择的部署方案
1).分布式探索系统。分布式的探索系统可以将组件部署到不同的机器,能够集中、合理地利用机器的算力资源,更新组件时也可以保证旧服务不停止的同时进行热更新。缺点是分布式系统的架构和设计比较复杂,开发成本高。部署方案如下图所示:
2).单机版探索系统。顾名思义,单机版的探索系统是指将探索地图所需要的各个组件都运行在本地,优点是全部组件可以自由开启关闭,本地随时修改。缺点是本探索系统所需要的计算资源较为庞大,单靠本地资源难以支撑整个系统的长期运行。
2.6 补充说明
1).维护:项目采用分布式的部署方式,并使用JMS消息中间件Active MQ,降低各组件之间的耦合度,这使各个组件容易维护;
2).设备:由于是支持分布式部署,所需设备数量可能增加,但对于各设备的硬件要求会降低;
3).局限性:使用Active MQ和Redis要求分布式部署的各个电脑在同一网段下。其次,并发性能仍有优化的余地,目前的系统性能未达到最优。
3. 软件设计说明书
3.1 软件体系结构图
1).整体传统架构图
整体传统架构图
2).层次架构图
层次架构图
3).分布式系统的部署或组件分布
本系统中黑板和消息队列可以独立部署到不同服务器,显示组件、导航器组件均可多处部署。我们小组鉴于陈怿文(PC2)生病修养的情况,将四个组件分布式部署到三台计算机,具体的部署情况是:
施荣鑫(PC1)运行view组件+navigator组件,SQL Server+Redis+部署MQ;
李斌(PC3)运行controller组件,启动MQ;
艾孜(PC4)运行car组件,启动MQ。
3.2 基于黑板风格的系统架构图
系统架构图
3.3 数据设计
3.3.1 数据库设计/外部文件描述
a.用户信息表user
用户信息表user | ||||
字段名 | 数据类型 | 数据长度 | 描述 | 含义 |
id | int | 12 | 主键,自增,不可编辑 | 用户ID |
name | varchar | 20 | 非空 | 账户名 |
passwd | varchar | 32 | 非空 | 密码 |
role | varchar | 12 | 非空 | 权限 |
b.本地现存地图信息表map
本地现存地图信息表map | ||||
字段名 | 数据类型 | 数据长度 | 描述 | 含义 |
id | int | 12 | 主键,自增,不可编辑 | 用户ID |
weight | varchar | 20 | 非空 | 地图宽度 |
height | varchar | 20 | 非空 | 地图高度 |
size_of_point | varchar | 12 | 非空 | 地图像素点大小 |
map_block | ntext | 非空 | 地图障碍物位置信息 |
c.回放地图信息表path_map
回放地图信息表path_map | ||||
字段名 | 数据类型 | 数据长度 | 描述 | 含义 |
id | int | 12 | 主键,自增,不可编辑 | 主键ID |
user_id | int | 12 | 非空,外键 | 关联用户ID |
weight | varchar | 20 | 非空 | 地图宽度 |
height | varchar | 20 | 非空 | 地图高度 |
size_of_point | varchar | 12 | 非空 | 地图像素点大小 |
map_block | ntext | 非空 | 地图障碍物位置信息 |
d.回放路径信息表path
回放路径信息表path | ||||
字段名 | 数据类型 | 数据长度 | 描述 | 含义 |
id | int | 12 | 主键,自增,不可编辑 | 主键ID |
user_id | int | 12 | 非空,外键 | 关联用户ID |
car_id | int | 20 | 非空 | 小车ID |
path | ntext | 非空 | 路径点信息 |
3.3.2 内存保存的数据结构描述
A)地图信息:使用一维的boolean数组表示。true表示有障碍物,false表示无障碍物;
B)小车位置:使用自定义的point类型表示;
C)路径列表:Java内置的List类型,List中存有自定义的路径点point类,包括X坐标和Y坐标。
3.3.3 共享数据结构描述
键 | 类型 | 含义 |
CarID:Explore | Set类型 | 该车探索的地图 |
CarID:Path | List 类型 | 该车探索的路径 |
CarID:Position | Hash 类型 | 该车的位置信息 |
CarID:RoutList | List 类型 | 该车即将要探索的路径点 |
CarID:States | List 类型 | 该车的状态信息 |
algorithmOfNavigator | String 类型 | 导航器的寻路算法 |
goalOfNavigator | String 类型 | 导航器的目的地选取规则 |
heightOfMap | String 类型 | 地图的宽度 |
widthOfMap | String 类型 | 地图的高度 |
sizeOfPoint | String 类型 | 地图像素点的大小 |
isAddCar | String 类型 | 是否增加小车 |
isAddNavigator | String 类型 | 是否增加导航器 |
mapBlock | String 类型(bitmap) | 地图的障碍物信息 |
mapExplore | Set 类型 | 地图已经被探索位置的点集合 |
mapView | String 类型(bitmap) | 地图被点亮位置信息 |
numOfCars | String 类型 | 当前正在探索的车辆数量 |
numOfNavigators | String 类型 | 当前正在工作的导航器数量 |
numOfNavigatorIdRout | String 类型 | 导航器Id目前的工作量 |
navigatorsRoutList | List 类型 | 正在申请导航器的CarId清单 |
3.3.4时序图
时序图
以时间为顺序的时序图,关于四个组件之间的交互,其中view为实时监控Redis里面数据来显示。
3.3.5多小车多泳道流程图
多泳道流程图
3.3.6寻路算法的关键组件以及函数接口
(为避免赘述,仅以A*算法为例,DFS和BFS算法同理):
1.start:起始节点
2.goal:目标节点
3.closedSet:集合,用于存储已访问过的节点
4.openSet:集合,用于存储待探索的节点
5.cameFrom:映射表,记录每个节点的上一步路径
6.gScore:映射表,存储每个节点的实际成本
7.fScore:映射表,存储每个节点的启发式估计成本
8.heuristicCostEstimate(node,goal):启发式函数,用于估计节点到目标节点的启发式成本
9.distanceBetween(current,neighbor):计算当前节点到相邻节点之间的距离
10.reconstructPath(cameFrom,current):通过回溯cameFrom映射表重构最佳
3.4 详细设计(模块描述)
3.4.1用户登录功能描述
1)功能;接受用户的输入,进行系统的登录。
2)接口:被上层用户管理子系统调用,不调用下层模块
3)数据:使用到SQL Server中的登录信息
4)处理:
用户登录功能流程图
3.4.2注册功能描述
1)功能;接受用户的输入,进行用户的注册。
2)接口:被上层用户管理子系统调用,不调用下层模块
3)数据:使用到SQL Server中的登陆信息
4)处理:
注册功能流程图
3.4.3路径回放功能描述
1)功能;加载地图和路径数据,并在界面中绘制出地图、路径点和小车的移动轨迹,同时提供开始、停止、重新播放等按钮以控制回放过程。
2)接口:
调用的模块:SQLConnectionPool类、JSONArray类、JSONObject类
被调用的模块:无
3)数据:
使用到SQL Server中的path_map表和path表
pathPointsList:List<List<Point>>对象,保存所有小车的路径点信息
currentPointIndices:int[]数组,保存每个小车当前的路径点索引
mapBlock:String(bitmap)变量,保存地图方块的数据
4)处理:
路径回放功能流程图
3.4.4地图生成模块描述
1)功能:具有三种生成地图的方式:①从数据库中得到已定义的地图数据,包括障碍物的信息和宽高等等;②在三种宽高不同的大小下,根据不同的随机算法生成地图上的障碍物,可以调整障碍物的数量;③自定义地图的宽高,还有可以随机生成一个障碍物或者在画布上指定位置手动添加障碍物。
2)接口:在显示界面上显示,不调用下层子系统
3)数据:使用SQL Server中保留的0-1字符串地图信息或是手动输入到里面地图信息
4)处理:
地图生成功能流程图
3.4.5小车移动模块描述
1)功能:具有生成小车的功能,包括初始设定小车和中途生成小车;根据小车当前位置以及Redis中规划的路径,在控制器的命令下,小车移动到下一个路径点。
2)接口:被上层多车运行实验子系统调用,不调用下层子系统
3)数据:使用到Redis中的关于小车的自身的信息和它完成的探索信息
4)处理:
小车移动功能流程图
3.4.6控制器模块描述
1)功能:开始探索后负责控制导航器生成小车任务和向小车发送移动信号。
2)接口:被上层地图探索子系统调用,不调用下层子系统
3)数据:使用到Redis中关于小车自身的信息和导航器任务情况
4)处理:
控制器流程图
3.4.7导航器模块描述
1)功能:接收控制器发来的信息,对小车进行路径规划
2)接口:被上层多车运行实验子系统调用,不调用下层子系统
3)数据:使用到 Redis 中的关于小车的自身的信息和它完成的探索信息
4)处理:
导航器流程图
3.5 运行效果展示
登录注册和初始化页面
四个图分别为登录页面,注册页面,功能选择主页面和进入生成地图时的初始页面。
生成地图的三种方式
三种生成地图的方式从左至右依次为:通过数据库导入地图,自定义手动设置地图,和选择尺寸、难度后随机生成地图。
小车探索的运行页面和回放页面
3.6 接口设计
3.6.1 软件接口:
使用的是黑板风格,分布式组件都是依靠Active MQ和黑板(Redis)进行耦合,并未对外暴露接口
3.6.2 分布式数据接口:
项目中使用到了Redis、Active MQ和SQL Server,将接口统一封装到SQLConnectionPool、RedisHelper和RedisPoolUtil中供各组件进行数据操作。
3.6.3 界面接口(部分接口的技术原理):
使用java中内置的JFrame类,使用单例模式进行界面的切换已经对于共享信息(用户信息)的存储。
自定义定制地图界面接口
调用自定义定制地图界面接口的例子
三、综合实验总结或结论
1.初步讨论
根据对实验进程的分析,经过激烈的讨论,我们小组初步达成了统一意见。
多车协同探索地图的基本逻辑框架如下:
在这个实验中,我们使用了Redis数据仓库和ActiveMQ消息中间件来连接四个组件,目的是降低组件之间的耦合度,增加内聚性,使各个组件能够独立运行。
实验开始时,View视图组件从Redis中获取消息,并实时将其显示在视图上。这可以通过与Redis进行通信来实现,以获取更新的数据并将其呈现给用户。
Controller组件负责读取Car的状态和任务数组状态,并在其自身内部进行判断。首先,它检查是否需要通NavigatorID队列来通知导航组件开始规划路径。如果需要导航,则Controller组件向NavigatorID队列发送通知,以触发导航组件的工作。接下来,它还检查是否需要通过CarID队列来通知Car组件开始探索地图。如果需要,Controller组件向CarID队列发送通知,以启动Car组件的探索任务。
当Navigator导航器组件接收到通知后,它根据获取的信息生成路径,并更新任务数据。通过与Redis进行交互,Navigator组件可以将生成的路径信息存储在适当的位置,并确保任务数据得到更新。
Car组件监听任务队列,等待收到行动路径的请求。一旦收到请求,Car组件执行相应的探索任务,并将自身的位置以及已经探索的位置信息发送给Redis。这可以通过与Redis进行通信,将相关信息存储在Redis中,以便其他组件可以访问和使用。
通过这种组件间的协作,实验中的各个组件能够独立地进行工作,并利用Redis数据仓库和ActiveMQ消息中间件进行通信。这样的架构设计帮助降低了组件之间的耦合度,使得它们可以独立地进行开发、测试和维护。同时,这种设计也增加了组件的内聚性,使得每个组件专注于自己的功能,并能够通过消息中间件进行有效的交互。
2.遇到的问题、不足之处
a.关于redis和activeMQ的连接,在单机部署成功运行项目后,着手做分布式部署的过程中遇到了一个问题:除了部署Redis的这台机子,其他主机通过IP远程访问Redis的时候都被拒绝了,我尝试了各种方法,最后通过更换端口为6378解决问题,看来应该是6379端口不对外开放的原因。它默认端口6379就是会拒绝外部连接,哪怕注释掉bind 127.0.0.1都不管用(注:直接打开redis-server.exe无法找到配置文件,用如下命令手动配置以特定配置文件开启redis-server redis.windows.conf);
b.Active MQ启动失败,我一开始以为是8161(61616)端口被占用了,但在网络监视器中发现并没有应用占用这个端口。于是我根据命令框报错信息回溯,经查找发现是因为我的电脑之前使用过Rabbit MQ,在后台运行了一个rel.exe,会占用启动Active MQ过程中需要用到的4972端口,把这个应用关了就能正常启动了;
c.关于小车开始添加及中途添加小车,我们在Redis中设置了两个量,一个供以小车的数量统计,一个是添加小车的布尔函数,中途添加小车实时监听那个布尔函数即顺利解决。
d.在运行程序的过程中,规划小车路径时,小车会在地图上多次瞬移,而非按照规划好的路径一步步移动,这是由于多线程的设计问题;
e.关于Redis连接,Redis连接的时候如果只是一个连接的话会出现资源竞争,导致报一个B cast long这样的错误,查询时出现了数据拥堵,于是换用连接池,问题解决;
f.总是在探索地图过程中,小车的消息队列CarId突然就不再被监听消费了,越来越多的控制器发来的“Next”消息堆积在CarId队列,相应的小车也不再进行移动探索了。我一开始以为这是MQ消费者car组件出了问题。但是检查半天之后我发现其实不是不消费了,而是消费消息步骤的上一个步骤——坐标点亮地图的功能卡住了,卡在了Redis断联,因为点亮地图模块的代码开了Redis链接却没有在数据写入完成后回收连接,我写了回收链接就解决问题了;
g.关于登录、注册、用户信息管理模块,我对用户密码做MD5加密。这样做保护了用户信息,但同时也导致超管和管理员查看用户信息表时,看到的用户密码是密文乱码而非明文。因为数据库里保存的信息就是密文,而且MD5加密算法是不可逆的,无法逆推出明文;
h.关于回放中,路径数据与当前加载的地图数据不匹配,导致回放时小车在错误的位置和路径上移动,经过检查,发现是SQL语句逻辑错误,误将user_id写成了id,改正之后问题得到解决;
i.由于数据结构只设计了各小车的路径点集合,没有设计时间节点记录,所以,对于中途加入的小车,无法体现时间先后顺序,即在回放时会和原来就有的小车同时开始探索,这也导致了直观上回放过程中小车可能会发生碰撞(事实上探索过程中并不会发生碰撞);
j.路径停止按钮响应不及时,影响用户体验;
k.原本设计组件任务的时候,因为考虑到小车组件一般是在多个客户端运行的,控制器则是在中央服务器部署,一般中央服务器的计算性能都优于客户端,所以作为组长,综合考量之后我才把小车组件的碰撞检测计算任务放在了控制器组件。但是经过王老师的指正,我们才知道原来我对部署情境的理解是不对的,控制器只做调度工作根本不需要优越的计算性能,部署在普通主机即可,因此计算碰撞检测的任务让各小车自己去做即可;
l.我做的导航器组件虽然用接口实现了两种目的地选择算法和三种寻路算法的抽象,节约了大量的冗余编码,我以为自己这样的编码风格已经足够良好了,但经过王老师的点拨,我认识到自己做的设计从架构层次看,无法做到目的地选择和寻路算法的解耦,还有改进的空间;
m.我的导航器和小车组件都是在主线程下开启while循环监听是否增加数量的,这样就无法实现在多台主机上分别启动多辆小车/导航器,改进方案是单开线程;
n.在导航器中需要读取Redis数据库中的mapBlock位图来获取地图障碍信息,我采用的是最传统的笨方法——1bit、1bit地取值转换,相对来说是最浪费时间的,在地图变大的时候会导致性能系统下降,恰好我的Redis数据库和导航器组件都部署在我这台计算机上,并不需要跨主机远程访问Redis,所以就感受不到这一缺陷。事实上,获取地图信息,应该采用二进制位和整型数的转换方法进行地图的读取。因为1整型为4Byte即32bit,能大大提升读取速度。
3.心得体会
在这个实验中,我们使用了Redis数据仓库和Active MQ消息中间件来连接四个组件,组件之间只通过消息中间件来传输必要的通信信息、数据结构,而不是单纯的函数调用,具体的逻辑处理动作放在各自组件中,各组件只需要不断刷新监听相应的消息队列,根据接受到的消息内容作出不同的逻辑处理即可。这样的模式能够降低组件之间的耦合度,增加内聚性,实现各个组件的分布式独立运行。通过这个实验,我们对分布式系统的设计和软件开发过程中的团队协作有了更深入的理解与体会。
例如通过使用Redis和Active MQ作为中间件,实现了组件间的解耦和独立运行。这种分布式架构设计使得系统能够更容易地进行水平扩展,新的组件可以相对独立地加入系统,并与其他组件进行通信。将不同的功能逻辑分成独立的组件,每个组件专注于自己的任务,比如对于消息队列,每个组件只需要关心自己侦听哪个队列,根据侦听到的内容作出不同的逻辑处理即可,而不需要关心这个消息是谁发来的;同样的,每个组件也只需要关心自己将消息发向哪个队列,而不需关心由谁来侦听消费,以及消费之后作何动作。
这种架构设计让代码更加清晰、模块化,并且易于各模块代码的编写人员进行单元测试。因为黑板风格架构的各组件之间的通信信号,本质上就是消息(字符串),每个组件的输入、输出其实都是字符串。在单元测试的时候只需要在MQ和Redis中手动输入一些测试数据,然后在相应的位置查看输出是否产生了预期的消息内容即可。
在未来的升级和扩展中,可以更容易地修改和替换单个组件,而不会对整个系统产生过大的影响。而且使用消息中间件可以方便地进行异步通信,各个组件可以根据自己的时间和能力进行工作。比如,当Controller组件需要通知Navigator组件开始规划路径时,它只需向对应的队列发送通知,而不需要等待实时响应,这样可以提高系统的响应速度和灵活性。
也体会到了Redis的优势,它是一个基于内存的数据存储系统,是非关系型的数据库,采用键值对的存储结构,将数据存储在内存中,因此具有非常高的读写速度和低延迟,并且采用了高效的数据结构和算法,使得在处理大量并发请求时能够快速响应。同时通过这次实验,我们亲身体验了软件生命周期中的各个环节,加深了对软件工程课程的理解,锻炼了独立分析、解决问题的能力,也体会到了团队交流和团队分工在软件开发中的重要性,如果没有经过充分的交流,那么在之后的设计与代码编写中将会出现许多问题。
也学习了MD5加密算法,我对登录模块、注册模块、修改用户信息模块的用户密码进行了MD5算法加密,这样即使数据库用户信息表数据泄漏,非号主就算拿到了密文也无法登录,因为密文又会生成密文,而且MD5算法本质是Hash散列,是不可逆的,也就是没有解密算法能从密文逆推得到明文。并且,通过之后的拓展学习,我还了解到了MD5算法加密的破解原理,一种明文只能对应一种密文,但不同密文可能(极低概率)会有相同明文,密文虽然理论上被“碰撞”到的概率极低,但仍可被破解,尽管还是不能破解出原明文,但通过“碰撞”获得相同密文得到的所有明文都可以用作伪密码绕过登录查验。
总之,通过本次实验,我们的程序编写能力有所提升,体验到了以前没有接触过的构架及实现方式,同时锻炼了团队协作和解决问题能力,对软件开发的整个流程更加熟悉,为以后的工作奠定基础。
最后,感谢王老师和陈老师的耐心指导与殷切教诲!我感受得到王老师是真真切切地本着对学生负责的原则对我们严谨要求、耐心引导,尽可能地帮我们找出不足之处,是为了让我们更好地提升自己的设计思维,而且王老师指出不足后并没有当甩手掌柜,他还会引导我们一点点地探索出改进方案,这真的让我受益良多。比如我做的导航器组件,虽然用接口实现了两种目的地选择算法和三种寻路算法的抽象,节约了大量的冗余编码,我以为自己这样的编码风格已经足够良好了,但经过王老师的点拨,我认识到了自己做的设计从架构层次看,无法做到目的地选择和寻路算法的解耦。又比如我读取Redis的地图信息是采用最传统的本方法,1位1位地读,王老师当晚验收结束后还特地在班级群里发了解决的对策······;陈老师也很热心负责,我们小组在做分布式部署过程中,Redis一直无法连接上,是陈老师主动过来帮我们查看问题,在陈老师的启发下,我才在当天下午找到了解决问题的对策。还有关于用户信息的加密,我也是积极将我的思路向陈老师求证,得到认可之后才实施,这帮我少走了许多弯路。
也感谢我的组员们对我工作的理解与配合!
四、参考文献
[1] 宋雨.软件工程基础. 机械工业出版社,2016.
[2] 郑仁杰,软件测试,人民邮电出版社,2011
[3] 王珊,萨师煊. 数据库系统概论(第五版).高等教育出版社.2014
[4] 王晓霞,宋雨,王翠茹.软件体系结构的性能评价研究[J].计算机工程与应用,2003.
[5] 王先国,UML 统一建模实用教程,清华大学出版社,2009