OO2021-第四单元作业总结及课程总结
1.总结本单元作业的架构设计
(1)第一次作业
本次作业,需要完成的任务为实现一个UML类图分析器UmlInteraction,学习目标为UML入门级的理解、UML类图的构成要素及其解析方法。
本次作业所实现的6个类如图所示:

各类的功能如下:
| 类名 | 作用 |
|---|---|
| Main | 主函数 |
| MyAssociation | 对UmlAssociation及其对应的UmlAssociationEnd进行封装 |
| MyClass | 对UmlClass及其对应的UmlAttribute、MyOperation、MyInterface、对端的UmlAssociationEnd等进行封装 |
| MyInterface | 对UmlInterface及其对应的UmlAttribute等进行封装 |
| MyOperation | 对UmlOperation及其对应的UmlParameter进行封装 |
| MyUmlInteraction | 题目要求 |
具体实现的思路是通过对UmlElement... elements进行2次遍历,将各种元素处理好之后,调用相关的查询方法即可。应当注意的是元素处理的顺序,第一次处理UmlClass、UmlInterface、UmlOperation、UmlAssociation,建立对应的MyClass、MyInterface、MyOperation、MyAssociation,第二次处理UmlParameter(加入对应的MyOperation)、UmlInterfaceRealization、UmlGeneralization、UmlAttribute(加入对应的类或接口)、UmlAssociationEnd(加入对应的MyAssociation)。然后再进行最后一次处理(针对对应的HashMap遍历),把MyOperation、对端的UmlAssociationEnd加入对应的类,考虑到查询的时候输入的是类名,又把之前以Id作为key的存储MyClass的HashMap用Name作为key存了一遍,方便针对类名的查询。
(2)第二次作业
本次作业,在上次作业基础上,扩展解析器,使得能够支持对UML顺序图和UML状态图的解析。
本次作业所实现的15个类如图所示:

各类的功能如下:
| 类名 | 作用 |
|---|---|
| Main | 主函数 |
| MyAssociation | 对UmlAssociation及其对应的UmlAssociationEnd进行封装 |
| MyClass | 对UmlClass及其对应的UmlAttribute、MyOperation、MyInterface、对端的UmlAssociationEnd等进行封装 |
| MyInteraction | 对UmlInteraction及其对应的MyLifeline进行封装 |
| MyInterface | 对UmlInterface及其对应的UmlAttribute等进行封装 |
| MyLifeline | 对UmlLifeline及其对应的UmlMessage进行封装(UmlMessage分为in、out两类,分开存储) |
| MyOperation | 对UmlOperation及其对应的UmlParameter进行封装 |
| MyRegion | 对UmlRegion及其对应的MyState进行封装 |
| MyState | 对UmlState/UmlFinalState/UmlPseudostate及其对应的MyTransition等进行封装 |
| MyStateMachine | 对UmlStateMachine及其对应的MyRegion进行封装 |
| MyTransition | 对UmlTransition及其对应的UmlEvent(trigger)进行封装 |
| MyUmlClassModelInteraction | 题目要求 |
| MyUmlCollaborationInteraction | 题目要求 |
| MyUmlGeneralInteraction | 题目要求 |
| MyUmlStateChartInteraction | 题目要求 |
(由于本单元作业中,UmlStateMachine和UmlRegion一一对应,所以也可以改为MyStateMachine直接管辖MyState。我写的时候还是按照UmlStateMachine-UmlRegion-UmlState的等级实现的。)
本次作业中,为了减少针对所有元素进行的遍历,在MyUmlGeneralInteraction里建立属性private HashMap<String, ArrayList<UmlElement>> elementMap,然后在初始化public MyUmlGeneralInteraction(UmlElement... elements)里进行:
elementMap = new HashMap<>();
for (UmlElement element : elements) {
elementMap.computeIfAbsent(
element.getClass().getSimpleName(), k -> new ArrayList<>()).add(element);
}
之后对于MyUmlClassModelInteraction、MyUmlCollaborationInteraction、MyUmlStateChartInteraction的构造,只需传入elementMap,处理所需元素对应的ArrayList即可(应该先判断一下输入数据中有无该类元素),比如:
if (elementMap.containsKey("UmlRegion")) {
for (UmlElement item : elementMap.get("UmlRegion")) {
MyRegion newOne = new MyRegion((UmlRegion) item);
myRegionHashMap.put(item.getId(), newOne);
}
}
(3)第三次作业
本次作业,在上次作业基础上,对模型进行有效性检查。
本次作业所实现的17个类如图所示:

各类的功能如下:
| 类名 | 作用 |
|---|---|
| ClassModelCheck | 结构与MyUmlClassModelInteraction相同,实现6个检查方法 |
| Main | 主函数 |
| MyAssociation | 对UmlAssociation及其对应的UmlAssociationEnd进行封装 |
| MyClass | 对UmlClass及其对应的UmlAttribute、MyOperation、MyInterface、对端的UmlAssociationEnd等进行封装 |
| MyInteraction | 对UmlInteraction及其对应的MyLifeline进行封装 |
| MyInterface | 对UmlInterface及其对应的UmlAttribute等进行封装 |
| MyLifeline | 对UmlLifeline及其对应的UmlMessage进行封装(UmlMessage分为in、out两类,分开存储) |
| MyOperation | 对UmlOperation及其对应的UmlParameter进行封装 |
| MyRegion | 对UmlRegion及其对应的MyState进行封装 |
| MyState | 对UmlState/UmlFinalState/UmlPseudostate及其对应的MyTransition等进行封装 |
| MyStateMachine | 对UmlStateMachine及其对应的MyRegion进行封装 |
| MyTransition | 对UmlTransition及其对应的UmlEvent(trigger)进行封装 |
| MyUmlClassModelInteraction | 题目要求 |
| MyUmlCollaborationInteraction | 题目要求,新增1个检查方法 |
| MyUmlGeneralInteraction | 题目要求 |
| MyUmlStandardPreCheck | 题目要求 |
| MyUmlStateChartInteraction | 题目要求,新增1个检查方法 |
其中,负责类信息查询的MyUmlClassModelInteraction和负责类信息预检查的ClassModelCheck,属性结构与构造方法基本一致,仅仅是分工不同。(为了代码风格检查,每个类不得超过500行)
在构造MyUmlStandardPreCheck时,传入MyUmlGeneralInteraction中构造完毕的ClassModelCheck(R001-R006)、MyUmlCollaborationInteraction(R007)、MyUmlStateChartInteraction(R008),针对不同检查调用不同方法即可。
2.总结自己在四个单元中架构设计及OO方法理解的演进
(1)第一单元
第一单元的任务是表达式求导。
在第一单元,我主要采用了根据不同运算符号将整个表达式进行拆分,然后构建表达式树的架构设计。具体而言,构建表达式树的过程为,根据加减号将输入字符串处理为各个项,再通过乘号将各个项处理为各个因子,最后处理各个因子,构造不同的常数、幂函数、三角函数、表达式因子(需要递归处理)。
之前接触的编程任务都是面向过程的,这一单元让我切实感受到了“面向对象”的含义。即,我们考虑的不再是“求导”这一过程本身,而是表达式因子、三角函数、幂函数等等这些“对象”的构建、处理。
(2)第二单元
第二单元的任务是电梯。
这一单元的主要难点在于多线程的实际应用,难点在于debug,我先后尝试了打印输出法和JProfiler两种方法(个人感觉还是使用打印输出法,在关于锁的操作前后加上不同输出,更加简单直白一些)。我的架构设计为,每个电梯都有自己单独的请求队列,调度器接受所有的乘客请求,然后根据乘客需求、电梯功能的不同,将请求发往不同的电梯请求队列,每部电梯只处理自己请求队列中的乘客请求。
本单元主要学习了多线程的实际应用,主要的难点在于确保多线程的安全性。在这一单元中,乘客请求队列、电梯调度器、电梯之间层次分明,分工明确,进一步加深了我对面向对象的理解。第二单元是我得分最高的一个单元。
(3)第三单元
第三单元的任务是JML。
本单元的主要任务是实现JML要求的功能,架构设计没有什么创新之处。
本单元强调的主要是规格二字,以规格为基础,结合自己的算法优化,才能正确高效地完成每一次的作业,绝对不是简单翻译JML规格,算法复杂度、测试等等都是需要格外注意的地方。本单元是动脑需求最低的一个单元,也是我得分最低的一个单元······
(4)第四单元
第四单元的任务是UML。
本单元采用通过自己新建的类封装部分UML元素,完成初始化中对所有元素的处理,之后调用解析器中各个查询方法的架构设计。主要难点在于对UML图各元素之间关系的理解,无论是代码实现还是错误排查,最后都要回归UML自身进行考虑。
在本单元,继承、封装、抽象、层次化设计等等面向对象的实现形式都得到了实际应用。各个层次的Java类职有专司,共同完成题目要求的功能,查询逻辑简单,函数调用清晰,增强了后续的拓展性和可维护性。
3.总结自己在四个单元中测试理解与实践的演进
(1)第一单元
数据生成:手动生成刁钻复杂的或者边缘化的数据。
结果验证:简单的直接手算结果,复杂的和同学的结果比对,后来又采用Python的库函数生成正确结果进行结果比对。
(2)第二单元
数据生成:手动生成刁钻复杂的或者边缘化的数据。
结果验证:把结果输出到文本文件,手动查询各乘客是否in、out。
(3)第三单元
数据生成:手动生成(较弱的)数据。
结果验证:与同学的程序对拍。
(4)第四单元
数据生成:手动生成数据。
结果验证:与同学的程序对拍。
事实证明,对程序进行有效的测试是确保正确性的关键。第二单元的多线程给我带来的威胁感最大,所以自己在课下进行的测试最多,提交上去的最终版本也不是很有把握,结果整个单元就错了一个测试点,其他点的用时也很短,反而是我得分最高的一个单元。而第三单元看似简单,所以我疏忽大意,没有注重测试,结果惨不忍睹。
4.总结自己的课程收获
-
在一定程度上掌握了Java编程语言的应用,进一步提高了自己的编程能力。
-
改变了大一学习的面向过程的刻板思维,学习了面向对象的相关知识,在12次的编程作业中对继承、封装、抽象、层次化设计等有了足够的理论认识与实际应用。
-
认识到了架构设计的重要性。在OO学习中,提前构思出优秀的架构设计,对于正确性与性能,都能起到事半功倍的效果。当然,有些时候可能写着写着才想到更好的架构,这时候就要舍得花时间重构。
-
认识到了测试的重要性。有几次作业的强测成绩不太理想,出错的bug都是在我写代码时考虑到了的,结果要么忽视了这些潜在的隐患,要么自信满满地相信自己的代码不会出问题,总之就是没有构造相应的数据去验证一下,导致强测出大问题;这些隐患之前思考过,所以bug修复阶段很快就能改正,这样就更让人后悔了,当时为什么不加强自测、主动发现问题呢?
-
经历了强测成绩的大起大落、互测攻防的腥风血雨,心理承受能力得到了锻炼。
总之,收获满满!
5.立足于自己的体会给课程提三个具体改进建议
-
实验课,编程题可不可以像公测那样显示测试点通过情况,填空题可不可以课后及时公布答案?如果没有反馈,就没法总结自己实验课的学习情况。
-
单元训练可以比每单元的第一次作业提前几天开放,便于预习。
-
最后一单元的作业还是和考期冲突,不利于充分的构思与测试。希望能够调整一下第四单元的作业结构。

浙公网安备 33010602011771号