要求
(1)总结分析自己实现规格要求所采取的设计策略
提示:设计策略一般指整体性的设计思路分析
(2)结合课程内容,整理基于JML规格来设计测试的方法和策略
(3)总结分析容器选择和使用的经验
(4)针对本单元容易出现的性能问题,总结分析原因
如果自己作业没有出现,分析自己的设计为何可以避免
(5)梳理自己的作业架构设计,特别是图模型构建与维护策略
提示:针对最终形成的架构进行分析,应和设计策略部分的相关阐述配合起来
设计策略
(1)总结分析自己实现规格所采取的设计策略
- 阅读往年学长博客,查看坑爹的地方。具体地说,在任意一篇总结博客中,
Ctrl+F
,“超时”。 - 通读规格,对整个project有大概的了解,尽量从自然语言的角度去理解规格。
- 调整规格使用的容器
虽然规格里都是数组,但是,我们必不可能跟它一样。所以,找到所有可以不用数组的地方,确定要使用的容器类型。 - 对规格方法的调整。
就像在第十次作业里,我们要手动维护ageVar一样,整个规格里,还是有很多方法有优化的空间,所以就尽可能地优化。 - 和同学交流,看看有没有什么比较坑的地方。
测试的方法和策略
(2)结合课程内容,整理基于JML规格来设计测试的方法和策略
这个问题问得非常有深度,让我有点把握不住,所以思索良久后,我打开了百度百科。
方法:
方法是一个汉语词汇,方法的含义较广泛,一般是指为获得某种东西或达到某种目的而采取的手段与行为方式。方法在哲学,科学及生活中有着不同的解释与定义。
策略:
指计策;谋略。一般是指:1. 可以实现目标的方案集合;2. 根据形势发展而制定的行动方针和斗争方法;3. 有斗争艺术,能注意方式方法。
感觉方法注重的是行为方式,而策略注重的是一类方法。
策略:面对要测试的对象,给定输入,保证输出的正确性。
方法:
- 用Junit对各个方法进行测试,输入的数据包括:合法数据、边界数据以及非法数据
- 当完成一整个project后,用测评机对整个工程进行测试
以上就是我能想到的测试方法。
容器选择和使用
(3)总结分析容器选择和使用的经验
- 注意到要我们实现的类中,很多都是有一个专有的ID,为了性能,Hashmap会被大量地使用。
- 有些容器在使用的时候,强调了“有序性”,比如获取一个Person的前四条消息,“前四条”就具有非常明显的顺序特征,所以使用了ArrayList。
- 有些容器是为了专门的算法而设计的,比如堆优化的迪杰斯特拉算法中的PriorityQueue。
以上三点就是我容器选择的考量。
至于经验,删除的时候使用迭代器就好了,没啥大的经验。如果高级一点的话,stream很不错。
性能问题
(4)针对本单元容易出现的性能问题,总结分析原因。如果自己作业没有出现,分析自己的设计为何可以避免
homework10/Network.java: isCircle()
可能出现性能问题,跟个人的实现方式有关。如果写得好,实际上dfs和bfs都不会出问题,没必要用并查集。关键在于,要把遍历过的点给收集起来,避免重复遍历。
使用并查集的话,,如果有一天该Network中某个人去见马克思了,得重新更新。
getValueSum()
同理。
homework10/Group.java: getAgeMean()
求平均数的函数。如果不做优化,复杂度为O(n),当Group中Person人数很多时,耗时间。
我的设计是在Group中维护一个ageSum,每当要对Group中的人进行增或删时,就同步修改ageSum
,要getAgeMean()
时,就返回ageSum/size
。这样就把复杂度降低到了O(1)。
getValueSum()
同理。
homework11/Network.java: sendIndirectMessage()
要返回两个Person之间最短路径的长度。
如果采用普通的迪杰斯特拉算法,复杂度为O(n^2),直接使用会超时。
我的设计是使用堆优化的迪杰斯特拉算法,复杂度为O(nlogn),所以没有超时。
架构
(5)梳理自己的作业架构设计,特别是图模型构建与维护策略
提示:针对最终形成的架构进行分析,应和设计策略部分的相关阐述配合起来
图(graph),说到底,就是节点(vertex)和边(edge)。
本次作业,Network中,我通过Hashmap<Integer, Person> personId2Person
来维护图中的节点。对于图中的边,则通过HashMap<Person, Integer> person2Value
来维护,为了方便我的isCircle()
,我还使用了ArrayList<Person>
来维护每个节点的邻接节点。
这个好处是体现了面向对象的思想。我记得在离散数学课程中,边的维护是依靠图中的三元组,而到了面向对象这门课里,让节点维护自己的边,类似于邻接表,这样更符合生活实际。
图模型的构建就是基于以上三种数据结构。
至于维护,只要保证增删改时,三种数据结构以及做了维护的ageSum
等变量被同步更新,特别注意删除时用迭代器。
总的来看,为了效率,特定去维护一些变量,这样可能造成某些方法考虑不周,导致维护不当而出错,所以要辅之以必要的测试,这应也是本单元的一个考察要点。
心得
互测就这样结束了,这是我唯一一次和其他同学对拍,感觉良好,三次作业都没出bug。
不过,,这样的结果就是被分配到比较强的互测屋,每次把别人的jar打包好,然后跑上测评机,一无所获。觉得心蛮累的。
还有就是契约式编程,当我们写一个函数的时候,要求考虑到各种情况,契约式编程把这种需求完整地表达了出来,虽然以后我们很少用JML,但是,对于我们思维的全面、少写bug,是很有帮助的。