BUAA_OO_Unit4_Summary & Course_Summary
目录
-
第四单元架构设计
-
第一次作业
-
第二次作业
-
第三次作业
-
-
四个单元中架构设计思维及OO方法理解的演进
-
第一单元
-
第二单元
-
-
第四单元
-
-
四个单元中测试理解与实践的演进
-
课程收获
-
改进建议
一、第四单元架构设计
本单元主要任务是UML解析器的射击,三次作业迭代,由类图->状态图和顺序图->UML预处理检查的顺序展开。
由于在设计中,UMLClass, UMLOperation,UMLAttribute, UMLParameter等类具有明确的树型关系,可以利用这一性质建立父子节点。而由于输入的UMLElement顺序是完全随机的,因此我们需要使用层次化处理方法进行读入处理。
第一次作业
第一次作业主要是关于类图。
第一轮处理 | 第二轮处理 | 第三轮处理 |
---|---|---|
UMLClass, UMLInterface, UMLAssociation | UMLAttribute, UMLOperation, UMLInterfaceRealization, UMLAssociationEnd | UMLParameter, UMLGeneralization |
为了更好地实现相关功能,我对部分元素类型进行了自定义封装:MyClass, MyInterface, MyOperation。
第二次作业
第二次作业新增了状态图与顺序图。
状态图:
第一轮处理 | 第二轮处理 | 第三轮处理 | 第四轮处理 | 第五轮处理 |
---|---|---|---|---|
UMLStateMachine | UMLRegion | UMLState, UMLPseudoState, UMLFinalState | UMLTransition | UMLEvent, UMLOpaqueBehavior |
顺序图:
第一轮处理 | 第二轮处理 | 第三轮处理 | 第四轮处理 |
---|---|---|---|
UMLCollaboration | UMLInteraction | UMLLifeline, UMLEndpoint | UMLMessage |
本次作业较为困难的地方在于寻找是否是关键状态,我采取的方法是dfs搜索
public void dfs(int pos) {
visited[pos] = 1;
path.add((char) pos);
if (pos == end) {
ans.add(path.toString());
}
else {
for (int i = 0; i < mapSize; i++) {
if (visited[i] == 0 && i != pos && map[pos][i] == 1) {
dfs(i);
}
}
}
path.remove(path.size() - 1);
visited[pos] = 0;
}
第三次作业
第三次作业在前两次的基础之上,添加了有效性检测。由于所有需要用到的元素在前两单元都已经建模完成,因此只需要按照要求进行九个有效性检测函数的设计即可。
本次作业中较为困难的就是循环继承的判断,考虑到类图元素为树形结构,因此在设计时采用了深搜递归方式进行判断,具体方法为搜索每条路径,如果路径上元素与起点元素相同,则存在循环继承。
public ArrayList<MyInterface> findPath(MyInterface myInterface, ArrayList<MyInterface> target) {
ArrayList<MyInterface> ans = new ArrayList<>();
if (target.contains(myInterface)) {
ans.add(myInterface);
return ans;
}
ans.add(myInterface);
for (int i = 0; i < myInterface.getParent().size(); i++) {
ArrayList<MyInterface> newTarget = new ArrayList<>();
newTarget.addAll(target);
newTarget.addAll(ans);
ArrayList<MyInterface> myInterfaces =
findPath(myInterface.getParent().get(i), newTarget);
if (hasSame(target, myInterfaces)) {
ans.addAll(myInterfaces);
return ans;
}
}
return ans;
}
另外在强测时R004指令(重复继承)出现了错误,让我百思不得其解,明明并不困难,感觉设计也没有出现漏洞。在仔细检查后发现原来是在前两次设计中,为了避免出现重复继承曾经在层次化读入阶段设计特判试图避免重复继承,没想到却在第三次作业中需要检测重复继承,因此出现了问题。
其余指令设计思路都不困难, 只要读懂指导书基本都可以顺利设计完成。
二、四个单元中架构设计思维及OO方法理解的演进
第一单元
第一单元的主题是表达式分析,其关键在于采用递归下降方式对表达式进行解析。
层次化设计:递归下降解析,将表达式划分为表达式,项和因子三个层次,在此基础之上进行复杂的计算,把每一个任务分成许多部分,每个层次完成属于自己的部分即可。仅仅需要必要的接口来完成数据交互,尽可能地实现“高内聚,低耦合”的目标。
迭代开发:可以说这是第一次接触迭代开发的任务,这样的任务并不是一蹴而就的,不能仅为了单独一次任务而设计,更要为未来持续的迭代做准备。如果设计架构不理想,很可能在后续过程需要进行不同程度的重构。
第二单元
第二单元的主题是多线程,利用生产者消费者模型进行设计。
安全:在多线程问题中的安全问题是重中之重,由于多线程本身具有的不确定性,需要通过加锁的方式进行公共资源的维护,保证操作的原子性。
交互:多线程问题中共享资源的交互,哪些资源是共享交互的,哪些资源是私有的;哪些资源可以同时访问,哪些资源需要加锁。
第三单元
第三单元的主体是规格化设计,通过JML语言约束进行代码编写。
契约式编程:深入理解JML语言,弄明白写下规格约束的人到底想要实现什么功能,在哪些地方进行限制,准确精妙的实现代码。
效率:在第三单元中TLE问题是一位常客,尽管我们完全按照JML进行代码编写,写出的代码也完全符合要求,但是依然会TLE,写出复杂度过高的算法。我们需要深入理解规格之后的真正内涵,在保证无误情况下尽可能优化算法。
边界性:本单元出现了大量异常抛出,这也是规格约束的一个特点,它规定了我们需要实现的功能,也同样规定了我们需要避免的可能出现异常的操作。
第四单元
第四单元的主题是UML,迭代设计进行UML解析。
第四单元似乎在架构上并没有太大的发挥空间,只需要按照要求进行一个个函数的设计即可。但是其中也有层次化设计的思想,例如在解析读入时分层解析等。
不过,在CheckStyle制裁下倒是体会了些东西,三次迭代的函数全部堆在一个类中显然是不合适的,我们需要将其按照功能职责分类,分别储存调用即可。
三、四个单元中测试理解与实践的演进
测试是OO课程中极为重要的一个任务,中测,强测,互测包括自己进行的测试都是在对程序进行各个维度的检测。
在第一单元,刚刚开学接触OO,还处于一个懵懵的状态,可以说即使是在截至之前顺利通过中测都是一项不小的挑战,因此更是没有什么精力去设计各种测试方式了,因此在第一单元采用的基本是手动构造方式,按照指导书的逻辑进行边界数据测试,对程序进行验证。然而人力毕竟是有限的,仅仅靠肉眼观察,头脑构造出的数据强度即使说得过去,但是覆盖度一定是不足的,这也就导致了在强测过程中出现bug,互测中被hack。
在第二单元,电梯调度纷繁复杂,多线程运行眼花缭乱,但是我明白已经不能再仅仅依靠手动构造样例了,在参考讨论区热心同学提供的评测机搭建教程后,在完成设计之余,勉强实现了一个简陋的评测机,不管构造出的数据如何,强度覆盖度如何,至少能跑了。当然第二单元还有轮询,超时的问题,不能仅仅看结果的正确性,还要对时间方面进行检测。
第三单元由于基本无法对结果进行正确性判定,所以采取的方法是数据生成+对拍。而合作在测试中起到了关键的作用,集思广益,构造更具有针对性的,覆盖面更广的数据;而对拍两个人固然可以,但是更多人进行对拍在更大程度上保证了结果的正确性。
而第四单元由于临近烤漆无心coding,加之离校返乡同学之间沟通难度加大,所以基本还是采用白盒测试思想,根据指导书要求和代码情况手动构造方式进行针对性测试。
从一开始只能手动构造数据到后来慢慢学会搭评测机,设计生成覆盖性强的数据,再到进行对拍保证结果正确性,可以说是不小的进步了。
四、课程收获
行文至此已是凌晨,似乎终于要和OO做一个告别。
回想起起初相遇,可以说是印象深刻,刻骨铭心。由于寒假一直在准备美赛没来得及做Pre,直到开学才匆匆做了几个pre任务,然而第一周的压力着实让人心惊,周五开始着手作业却毫无头绪,脑袋里充斥着“瓦罐不离井上破,将军难免阵前亡”的念头,刚准备行走“江湖”,却没想到出门就要栽了跟头,焦头烂额直至凌晨才理出些头绪,早上爬起来继续做总算在下午完成。
即使OO在本学期的每一周都在各个方面给予我各种压力,让我不胜其扰苦不堪言,却也不得不承认这是一门好课。正如我在第一单元的博客中提到过,任何事情都是有利有弊,有得有失的,每当你你得到一些东西就会失去一些东西,反之当你失去了一些东西也会得到一些东西。在每周巨大的任务量之下,码力upup自不用说,更多的则是思维上的收获,无论是架构思维,迭代设计,测试思维都将在未来的代码旅程中起到重要的作用。当初进入计院,也就是为了能够在如此精品的课程的巨大压力下一边呻吟,一边前进,如今也算是求锤得锤了吧。
想想十六周的课程,十六次作业,似乎我一直在被追着跑,这是我很反感的。我讨厌毫无意义的忙碌,毫无意义的付出。但是回想一下旅途,即使在路上咒骂着路途的遥远,路上的艰险,但是一路上似乎也并不是没有收获的。
学习知识,初衷似乎就是在万水千山走遍,击败奥特曼或是小怪兽到达终点打开宝箱,享受着一路的艰辛痛苦换来的荣耀喜悦。
然而当我走过这条路之后,发现面前并无宝箱,也无宝藏,甚至也不是终点。
我的面前,只是另外一条路。
但是至少,在路上我捡了一些漂亮的贝壳。
五、课程建议
-
上机增加反馈机制,如上机后一两天公布成绩/答案。OO上机是快乐上机,比起上学期的计组上机轻松快乐的多,但是上机缺乏反馈机制属实让人犯难,首先在我眼中,上机内容是服务于每周任务,甚至是起引领作用,但是如果没有成绩或答案,万一上机写的有问题还不自知,还会造成后续实验出现问题。
-
互测环节数据查重。学习过程中的合作毫无疑问是可取的,相互交换理解可以更好的理解知识。但是在互测环节应当是自己通过阅读代码,进行思考,设计测试样例的过程,在付出以上之后hack到人得到分数奖励。但是也需要禁止无脑分享hack数据的行为。对于一些同学组成团体,共享测试数据在互测过程中使用的行为,我不知是否合理。
-
第三第四单元,适当增加JML和UML相关训练。JML实验更多偏向于读懂,而缺乏了写的过程;UML单元虽然确实加深了对UML的理解,但是也让人耗费许多精力在研究各种细枝末节之处。
-
在研讨课的汇报环节,增加老师助教提问。在研讨课每一小组的同学大部分都是不太愿意上台的,即使抽签上台也只是照本宣科将讨论内容复述一遍,而大多数场下同学也由于或者是早上困,或者是没认真听的缘故少有提问。建议增加老师助教,并对汇报同学适当加分,从而增加大家积极性
结语