OO第四单元总结即最终章
OO第四单元总结
本单元两次作业的架构设计
第一次作业
设计思路
- 对必要的
UMLElement
类型进行包装,增加必要的属性 - 建立必要的数据集合用于查询指令
- 基于数据集合实现查询
设计技巧
- 基于
HashMap
结构使用id
作为key
来组织数据 - 使用工厂方法使用对应类型的
UMLElement
来建立包装后的类型 - 根据关联关系,继承关系构建树形结构
设计图示
第二次作业
设计思路
- 同理对必要的
UMLElement
类型进行包装 - 建立三个相对分离的数据库支持不同数据的查询
- 基于三个数据库实现查询
设计技巧
- 使用
tarjan
算法实现对是否有循环继承的判断 - 使用广度优先搜索实现对状态的后继可达状态的查询
设计图示
四个单元中架构设计及对OO方法理解的演进
第一单元
在第一单元刚接触OO
思想时,这个转变的过程其实还是比较艰难的,所以在第一次作业中使用了比较面向过程的方法,从第二次作业开始,听从老师的意见开始在设计上大下功夫,尝试着使用OO
方法去解决问题
第一次作业设计
面向过程型的程序实现,在第二次作业时果断重构
第二次作业设计
第三次作业设计
经过第一单元的磨炼,感觉摸到OO
设计的一些基本的原则,也基本尝试了一些继承,接口,泛型的特性来实现统一,简洁的代码,个人感觉最大的收获是思维的初步转变 :
- 面向接口而不是实际的对象
- 注重继承关系,充分发挥泛型的作用,准确地抽象出共性
- 明确类的边界,注重消息的传递
第二个单元
从第二个单元开始,辛劳的助教团队提供了标准的输入输出接口,我们可以将更多的精力放在对具体业务逻辑的处理上而不是对输入字符串的处理
这一单元引入了多线程这一全新的概念,出现了死锁,错误不可复现等等十分麻烦的问题,使我们除了在设计架构上的注重外,还要对多线程的运行机制有一定的了解
在三次作业中我的设计思路是一脉相承的 :
- 主线程接受输入,每个电梯作为一个线程
- 主要的业务逻辑由调度器完成,根据需要分类业务逻辑,构造多级调度器
- 分离实际请求与电梯行为,电梯只接受调度器的上下简单指令
第一次作业设计
第二次作业设计
第二次作业设计
我个人觉得这个单元的收获处了巩固了OO
的设计思维之外,更多的收获是对多线程的理解上 :
- 如何设计一个好的线程安全类,在该作业中表现为请求队列这个类的设计上,这也是我花费时间最多的地方
- 如何平衡安全与效率,这主要表现在对上锁区域的把控上,要充分发挥出并行的优势
- 如何正确使用
wait
,notify
,sleep
等线程方法,这需要对java
多线程的机制有深刻的了解
第三个单元
这个单元引入了JML
这个全新的模块,这种规定显式的分离了调用者与实现者的责任,使得设计层次更加清晰,本单元我最大的收获并不是在代码实现中的,而是在对课程组提供的JML
的理解上,来学习这种功能分层次的设计
第一次作业设计
将MyPath
设计为不可变对象 :
- 使用
ArrayList<Integer> nodes
结构保存节点序列 - 内部维护一个
int distinctNodeCount
来保存一个Path
中的不同节点数目,该值在构造函数中初始化之后不再改变 - 使用
HashMap<Integer, Path> pathList
与HashMap<Path, Integer> idList
来实现Path
与PathId
的双向映射 - 使用
HashMap<Integer, Integer> nodeCount
保存不同节点的出现次数
第二次作业设计
基于上次作业的MyPathContainer
构建MyGraph
,新增数据结构GraphData graphData
GraphData
用来管理由路径容器生成的图的数据
HashMap<Integer, Integer> nodeToIndex
: 将整数类型范围内的节点离散化映射到0-120
的范围内int [][] graph
: 二维数据存储图的数据,值代表两个节点之间的路径数目int [][] dis
: 二维数据存储最短路径,值代表两个节点之间的最短路径
第三次作业设计
对每种功能需求建立一个图,图的边的矩阵的权值代表的含义即是需求(不满意度,票价,换乘次数)
第四个单元
见前文
对OO的理解演进
经过四个单元的训练,我也算是实现了从对OO
一窍不通的小白到了可以初步应用这种思想解决问题的成长,对OO
的应用的理解上,我个人主要有以下认识 :
- 高内聚,低耦合的设计理念,在实际编码之前一定要明确类的功能边界,反复考虑功能层次划分的合理性,既要符合实际情况,也要符合一定常识,在实现的简洁性与设计的规整性之间要做好权衡
- 代码的可扩展性,这得益于
OO
课程的每一单元的训练都是迭代式的开发,所以代码的良好扩展性十分重要,这一方面要求我们即对后续需求进行合理的猜想,另一方面要求我们在实际功能实现的过程中尽可能解耦 - 合理的应用前人的知识,在
OO
作业的完成中,前人总结的设计模式给了我很大的帮助,这些千锤百炼的模型给了我解决问题的许多思路或者启发,也使得我的建构设计有着良好的大框架,不拘泥于设计模式,合理应用必可事半功倍 - 面向接口编程,将上层对功能的使用与底层对功能的实现两个过程分离开来,这一实现形式对代码的可扩展性十分友好,也有效的提高了代码的复用率
其实OO
理论上就是对象以及对象之间消息的传递,但是将其应用到实际代码中去对我一开始还是很有难度的,只有经过实践,总结,在尝试中才能形成自己的一套对OO
理解的思维模式
四个单元中对测试的理解与实践
-
大规模随机数据生成 + 自动化测试
大多数情况下均使用的方法,根据输入的格式要求随机生成输入数据,或者根据标准程序的结果(例如
python
中有对第一单元函数求导的标准程序),或者同学们之间的结果进行比较来寻找bug
- 优点 : 简单,解放双手,在大量的数据投喂下命中错误的概率还不错
- 缺点 : 效率低,随机生成程序要考虑的很全面才有一定作用
-
基于
JML
测试在第三单元中使用,是一种对形式化验证的尝试,可以测试到很多人思维的漏洞
-
使用
Junit
人为构造数据集覆盖测试个人认为该方法是最有效的测试行为
- 构造数据时根据可能发生的情况的树状结构来尽可能对所有情况进行覆盖
- 在模块完成之后可以及时进行单元测试
- 使用
Junit
框架可以一次构造完成之后在对bug
的修复过程中可以方便的进行回归测试 - 根据
Junit
框架的覆盖率与覆盖范围可以对数据进行进一步的补充
缺点 : 工作量很大,我通常对数据的构造是与同学协作完成
课程收获
- 对
OO
思想与方法有了初步的认识,可以初步使用这种思想去分析基本的实际需求问题 - 提高了工程能力,对较多的代码不管是在实现上,还是在
bug
的定位与修复上都有了一定的经验 - 更好的编程习惯,经过无数次血的教训,开始代码未动,设计先行,开始主动的去单元化测试等等
对课程组的意见
- 指导书的样例更加全面一点,因为语言的二义性导致总有理解上的偏差,但是样例的结果却只有一种
- 个人认为研讨课的作用不是很明显,或许可以换一种形式,不是分享而是讨论
- 课上实验课的时间主要以完成任务为主,但是我个人觉得课上的一些例子是很典型的,应该课下也尽量开放但不可提交,让同学们有时间看看