OO第一次博客

代码分析

以第三次OO作业的代码为分析对象。

度量分析

类图

灰线为包内关联,红线为跨包关联。 详细类图。

自我评价

一些花了心思的设计

  • Registry类的设计是源于我注意到我有遍历所有实现了Busyable, Commandar接口的对象的需求。故而利用工厂方法,使得所有实现了某个接口的对象在完成对象构造后会将自己注册进对应的Registry中。之后只需要访问对应的Registry就可以遍历所有实现了该接口的对象。
  • AlterCenter类的设计是因为我注意到电梯自身对于指令也是有处理优先级的,这一部分逻辑不必放在Command类中进行处理。剥离出这部分逻辑可以使得Lift类在多指令源的环境下依然健壮执行,也简化了调度逻辑。
  • Commandar接口与Busyable接口的设计,与Registry类的结合,将原本不得不在编码在调度中的逻辑分散到了各个Commandar,Busyable实现类中,极大地简化了指令获取的逻辑与程序运行结束的逻辑。

自我检讨

  • Command类同时承担了对输入的解析与电梯运行逻辑的执行,显得过于臃肿。或许引入一个Inputer来剥离对输入的解析,使得Command类变成与IO无关的类是个更好的做法。
  • Outputer仅仅作为一个字符串处理的方法集合存在,实际的输出零散在各个类中,当需要更改输出方式的时候,我就把自己逼到死路了。或许使Outputer更充实一点,将输出逻辑更进一步地封装在Outputer中是个更好的做法。
  • 所有的异常都是以RuntimeException形式存在,在异常处理的时候无法从异常对象中更进一步地获取信息,也无法在捕获异常的时候根据异常类型区分处理。或许派生出属于自己的异常时个更好的做法。
  • 过于单薄的Building类,因为原本并不存在这个类,但我注意到CommandQuery, Floor, Lift之间需要一层更高级的类来绑定它们,使得它们能抱成团。但是在之后的版本更迭中我忽视了Building类的存在,并没有将CommandQuery, Floor, Lift类的交互逻辑抽象进Building类中。
  • Timable类的设计显得局部。本意是因为需要模拟时间,所以引入一个“该对象会随时间自动发生变化”的抽象接口,但是并没有为其准备充分的资源。像是如果时间流逝的时候两个对象需要发生相互作用之类的情况并没有考虑进去,而仅仅只是用来进行Lift类的状态更新与World类的时间流逝。

分析自己被找到的bug

但我公测和互测都没被找到bug……


代码测试策略

1.利用测试样例覆盖bug

利用编写的样例集,试图覆盖到程序的bug。

大多数时候是有效的也是唯一的手段,哪怕通过其他手段发现了可能的bug,最终也是用测试样例来确实地认定bug。

但是测试样例不可能覆盖到全部可能,一些出现条件苛刻而复杂的情况难以被覆盖到。

故而利用测试样例覆盖bug只能作为刚拿到程序时的摸索手段,或利用其它手段测试完程序后对bug的验证手段。

2.检查代码逻辑部分

检查代码的if,while等逻辑部分的处理是否正常。

大多数的bug都是出现于代码逻辑部分,故而优先检查if的判断语句、while的判断语句等逻辑语句是否正常,往往比较容易定位到代码的bug所在。

但是代码中的逻辑部分过于庞大、复杂,逻辑互相嵌套导致复杂度爆炸的情况也普遍存在,导致更多时候并不能完全确定逻辑部分代码的正确与否。

故而检查代码的逻辑部分这一手段仅适合用于局部逻辑的检查,不适合大规模代码的测试。

3.绘制控制流图

将代码中有大量判断分支的逻辑块绘制成控制流图,通过检查流图是否有缺支来寻找bug。

复杂的判断嵌套容易导致逻辑上的遗漏,通过绘制控制流图,有条理地分析每一个节点应有的逻辑分支,有助于发现被遗漏的分支。

无法处理过于复杂的逻辑,当因为递归、嵌套循环等而导致复杂度爆炸时,难以简单地利用流图表示。

故而控制流图仅适用于字符串处理等线性逻辑的代码分析。


心得体会

第一次维护需要给别人看的代码(笑),以前就算是要维护代码,也只是维护一些自己用的小程序,所以很多地方都是“这么搞也没关系,反正以后我也不会加那种功能”。但是这次面临的是未知的下次作业,以及随时可能更新的需求说明,所以每次OO作业都需要在完成本次作业的前提下尽量留下下次作业的余地,以避免逐渐把自己逼到走投无路、最后胡乱重构一气的下场。

一点对类设计的想法

我所遵循的设计流程是(一般都是边散步边在手机上做的x):

  1. 研读需求
  2. 构造平凡样例,检验对需求理解的正确性
  3. 构造非平凡样例,再次检验
  4. 从需求中抽象出主要的几个类
  5. 划定主要类的逻辑分工,同时抽象出BC,Interface等逻辑基类
  6. 安排主要类的主要属性的结构、对外的主要接口
  7. 脑内模拟跑样例,检查主要类设计的正确性
  8. 设计辅助类,充实主要类的属性、接口,同时检讨类设计的可行性
  9. 脑内模拟跑样例,检查类设计的正确性

一些可能与他人不太一样的设计想法:

  1. 在开始编写之前,我会尽量在时间允许的条件下写一些样例来对设计进行测试,以确保设计的正确性。编写测试样例的过程本身也有助于对需求的解读。
  2. 类的层次结构在主要类被抽象出来的时候就被确定了。我尽量避免在设计过程中变更类的层次结构,它牵涉到设计的方方面面,我会尽量最先确定下来它。
  3. 可行性的判定我会在编写前就尝试进行。大多数宏观的想法可以在设计过程中就验证是否可行,没必要放到编写时再进行。

一点对测试的想法

  1. 可以边读代码边写测试样例。代码中的许多逻辑分支其实就和输入分支树的分支一一对应。
  2. 自动化测试手段相当重要。因为我们的作业时间极其有限(一般来说周末写完,也就周一到周三的晚上时间可以debug,还不算文档撰写、其他课的作业的时间),重复劳动浪费的时间在总工作时间中占的比例相当可观。写一些自动化的测试脚本啥的可以说是一劳永逸。

 

posted @ 2018-03-31 19:10  青所  阅读(242)  评论(2编辑  收藏  举报