标签:sdn http 接口 排除 work 性能 建图 偏差 调用
这单元真是暗流涌动。
? ——沃兹基-硕德
你们要相信自己已经学过很多东西了,所以你们要多花精力去思考一些问题,把自己学过的东西融会贯通起来。
? ——王旭老师
我实现规格的策略是:
我个人认为自己的这种策略的主要缺点在于容易陷入已有的思维定势中,从而可能导致规格理解错误。
读规格的过程中,遇到的困难主要是规格太长,读了十几行就会忘掉,所以要读好几遍才知道这个方法到底是干啥的。另外还有个隐含的困难是,如果这个软件的功能自己之前没接触过,不清楚咋建模的话,那么读规格可能和读代码一样难以还原出整体的设计。这单元作业的图模型及其操作大家可能比较熟悉,所以没出现很明显的第二个问题。
关于测试方法和策略,由于有已经保证了正确性的规格,所以我的测试思路是这样的:
简单来说就是:重读规格,对拍,测极限数据。
值得一提的是,虽然老师这个单元非常强调要做单元测试,并且我在第一单元就有了使用junit进行单元测试的经验,本单元理应会用它,但是我尝试了一次之后发现在这单元使用有些多余和鸡肋,原因是我发现设计单元测试用例的时候似乎只需要阅读规格重新理解需求即可。如果重读的时候规格理解错了,那么单元测试的时候设计出来的用例肯定也错了,这种原因导致的bug很可能只有和别人交流规格的理解或者暴力对拍的时候才能发现;如果重读规格的时候读对了,那么顺手就能看出来代码实现的对不对(可能还是项目的规模比较小)。所以我认为对于这单元的作业来说,只要仔细理解规格并且进行对照就可以完全起到单元测试的效果。但是以后开发更大的项目并且没有JML这种相对严谨的规格描述的时候,那么单元测试将会非常非常有必要。
关于容器的选择,首先我们要知道每个容器主要是基于我们学过的哪种数据结构来实现的,然后阅读规格,观察我们需要对数据做什么样的操作,最后再决定到底使用什么样的容器。下面举几个例子:
Person
中的queryValue
方法,需要快速查找某个id
的人是否和当前人是连接的,如果直接连接则返回边权,这种随机访问且键值对中键不适合用数组下标表示的时候就比较适合用HashMap
去实现快速查找。所以在存储邻接表的时候,每个头结点对应的“邻接链表”完全可以使用HashMap
去实现,不一定局限于使用链表。Person
中Message
的存储,可以发现getReceivedMessage
对其有顺序的要求,以及Network
中发送信息的方法要求将新的信息头插到Person
的Message
中,且我们从不需要遍历这部分信息,所以可以考虑使用LinkedList
存储Message
。Message
,Network
中Message
则要求我们快速增删和查询,所以这里用链表就比较低效了,可以换做Map
来实现。在使用容器的时候,建议对某个操作不熟悉时仔细阅读文档并查看实用的教程,从而避免对容器的操作产生误解。说实话这单元最让我感觉没底的地方就是容器的操作,我生怕容器会做一些我没有注意到的事情导致结果错误,而这种错误通过对照JML是根本看不出来的(容器的操作都是抽象的,水很深,我怕自己把握不住呀)。比如在第9次作业中,某位同学向我反映遇到的问题是ArrayList的remove方法调用问题,ArrayList
包含两个remove
方法:
public E remove(int index);
public boolean remove(Object o);
如果是ArrayList<Integer>
的话,调用remove
方法的时候,假如是remove(id)
这种传入int
类型的id
,调用的是第一个方法,如果这个时候我们期望删除的是元素1
,那么将执行错误的方法。这个时候就需要使用包装器包装之后再调用方法。连大多数人自认为的Java容器中最熟悉的ArrayList
都能摆我们一道,可见在使用别人的东西的时候要有多小心。
关于性能问题,笔者在本单元并没有因为性能问题而失分。之所以能避免这些问题,原因有以下几点:
dijkstra
算法。qbs
的数据,第二次作业中卡没使用缓存的qgav
,第三次卡裸的dijkstra
。name_rank
指令不超过333条,所以不需要使用平衡树等数据结构动态维护。架构:这一单元我自己没有进行架构的设计,架构基本已经被官方接口定好了,下面只展示一下第三次作业中官方接口的架构是什么样的:
我只是把官方接口都简单地实现了一遍,用接口类型引用自己实现的类的实例而已。
建图的话通过阅读规格,最终确定使用的存储结构是动态邻接表,单个的邻接链表使用的不是链表而是HashMap
实现的,头结点列表使用的也是HashMap
实现的。
维护图就是通过理解规格,使用相应的图的基本操作(增删改查)来维护图中的信息,在有必要的时候使用数据结构(现有容器或者自己手搓)或者缓存等技巧加速维护。
虽然已经通过接口把架构几乎定死了,但是在具体实现的时候,我们可以采用任意合理的实现方法(比如想要优化的话一般需要在规格的基础上多维护一些数据),并且在需求变复杂的时候可能需要进一步建立层次关系(比如表情信息可能还会分为默认表情和自定义表情,红包还分为拼手气和普通红包)。可惜本单元的作业没有像前两个单元的作业那样逼迫我们不得不去进一步建立层次关系(这个痛点,它不够痛),即使需要建立,可能规格中也会有所体现(比如增加接口继承),不太需要自己去想。
如果能有比较完备的证明设计的正确性的工具(吴佬gkd),并且有通过规格自动生成代码的工具,那么以后人们只需要把精力集中在设计上就可以了。就算只能做到第一点,那么写代码也只是个体力活和时间问题。可是实际开发的时候JML的编写成本可能比较高,验证起来也有一定的困难,并且,实际开发的产品投入应用的时候性能势必是一个很重要的问题(想想选课网站),这就导致规格和代码实现有时候不能很好地对应,可能会导致bug的产生(这也是这个单元最刺激的地方了)。
要是工作时能对着JML写代码就好了。
单元测试和JML还是应该早些广泛宣传。早介绍的好处个人认为有以下几个:
本单元的作业主要还是考察是否细心,一方面是细心读规格,另一方面是细心做测试,二者只要能做好一个,那么应该就不会翻大车。但是从学习知识和技术的角度而言,我们最好还是要学会咋写规格,以及多读一些写得比较好的测试代码,学习如何写更优秀的测试。更重要的是,学会把自己学过的东西和实际问题联系起来,多思考,切忌纸上谈兵,切忌以完成作业为目标而得过且过,OO课的东西绝对不只是完成作业时体会的那些。
标签:sdn http 接口 排除 work 性能 建图 偏差 调用
原文地址:https://www.cnblogs.com/BUAA-Wander/p/14827667.html