经过一个月的学习,我对 OO 这门课有了一定的感悟,希望在这里做一个小小的总结。
前几次作业最普遍的问题就是边界错误,例如,第一次作业我测试的代码将 $20$ 个多项式判成了 $21$ 个,第二次作业我的代码将 $100$ 个多项式判成了 $101$ 个,这通常是判断边界时 $>(<)$ 和 $ge(le)$ 没有用对导致的。其它问题主要包括算法设计上出错等。
下面作一些具体的分析。
基于度量分析程序结构
第一次作业
类图
- 优点:抽象层次较为清晰
- 缺点:编程难度较大
度量
Method metrics | |||
method | ev(G) | iv(G) | v(G) |
polynomial.Main.main(String[]) | 1.0 | 3.0 | 3.0 |
polynomial.Poly.add(Poly) | 1.0 | 4.0 | 6.0 |
polynomial.Poly.Poly() | 1.0 | 1.0 | 1.0 |
polynomial.Poly.Poly(Term[],int) | 1.0 | 1.0 | 2.0 |
polynomial.Poly.print() | 6.0 | 4.0 | 7.0 |
polynomial.Poly.sub(Poly) | 1.0 | 5.0 | 6.0 |
polynomial.Processor.process() | 9.0 | 4.0 | 13.0 |
polynomial.Processor.Processor() | 1.0 | 1.0 | 1.0 |
polynomial.Processor.Processor(String) | 1.0 | 1.0 | 1.0 |
polynomial.Processor.processPoly(String) | 8.0 | 3.0 | 11.0 |
polynomial.Processor.processTerm(String) | 7.0 | 2.0 | 9.0 |
polynomial.Term.add(Term) | 1.0 | 1.0 | 1.0 |
polynomial.Term.compareTo(Term) | 2.0 | 1.0 | 5.0 |
polynomial.Term.getCoe() | 1.0 | 1.0 | 1.0 |
polynomial.Term.getExp() | 1.0 | 1.0 | 1.0 |
polynomial.Term.minus() | 1.0 | 1.0 | 1.0 |
polynomial.Term.Term() | 1.0 | 1.0 | 1.0 |
polynomial.Term.Term(int,int) | 1.0 | 1.0 | 1.0 |
Total | 45.0 | 36.0 | 71.0 |
Average | 2.5 | 2.0 | 3.9444444444444446 |
Class metrics | ||
class | OCavg | WMC |
polynomial.Main | 1.0 | 1.0 |
polynomial.Poly | 4.0 | 20.0 |
polynomial.Processor | 6.2 | 31.0 |
polynomial.Term | 1.5714285714285714 | 11.0 |
Total | 63.0 | |
Average | 3.5 | 15.75 |
Package metrics | ||
package | v(G)avg | v(G)tot |
polynomial | 3.9444444444444446 | 71.0 |
第二次作业
类图
- 优点:结构安排较为合理
- 缺点:设计过于复杂
度量
Method metrics | |||
method | ev(G) | iv(G) | v(G) |
elevator.Elevator.Elevator() | 1.0 | 1.0 | 1.0 |
elevator.Elevator.getTime() | 1.0 | 1.0 | 1.0 |
elevator.Elevator.move(Floor) | 1.0 | 1.0 | 6.0 |
elevator.Elevator.waitUntil(long) | 1.0 | 1.0 | 1.0 |
elevator.ElevatorRequest.commandFloor() | 1.0 | 1.0 | 1.0 |
elevator.ElevatorRequest.ElevatorRequest() | 1.0 | 1.0 | 1.0 |
elevator.ElevatorRequest.ElevatorRequest(Floor,long) | 1.0 | 1.0 | 1.0 |
elevator.ElevatorRequest.sameAs(Request) | 2.0 | 1.0 | 2.0 |
elevator.Floor.equals(Floor) | 1.0 | 1.0 | 1.0 |
elevator.Floor.Floor() | 1.0 | 1.0 | 1.0 |
elevator.Floor.Floor(int) | 1.0 | 1.0 | 1.0 |
elevator.Floor.Floor(long) | 1.0 | 1.0 | 1.0 |
elevator.Floor.getFloor() | 1.0 | 1.0 | 1.0 |
elevator.FloorRequest.commandFloor() | 1.0 | 1.0 | 1.0 |
elevator.FloorRequest.FloorRequest() | 1.0 | 1.0 | 1.0 |
elevator.FloorRequest.FloorRequest(int,Floor,long) | 1.0 | 1.0 | 1.0 |
elevator.FloorRequest.sameAs(Request) | 2.0 | 2.0 | 3.0 |
elevator.Main.main(String[]) | 1.0 | 7.0 | 7.0 |
elevator.Processor.process(int) | 22.0 | 22.0 | 30.0 |
elevator.Processor.Processor() | 1.0 | 1.0 | 1.0 |
elevator.Processor.Processor(String) | 1.0 | 1.0 | 1.0 |
elevator.Queue.elementAt(int) | 1.0 | 1.0 | 1.0 |
elevator.Queue.front() | 1.0 | 1.0 | 1.0 |
elevator.Queue.isEmpty() | 1.0 | 1.0 | 1.0 |
elevator.Queue.length() | 1.0 | 1.0 | 1.0 |
elevator.Queue.pop() | 1.0 | 1.0 | 1.0 |
elevator.Queue.push(E) | 1.0 | 2.0 | 2.0 |
elevator.Queue.Queue() | 1.0 | 1.0 | 1.0 |
elevator.Queue.resize() | 1.0 | 1.0 | 2.0 |
elevator.Request.commandFloor() | 1.0 | 1.0 | 1.0 |
elevator.Request.getAns() | 1.0 | 1.0 | 1.0 |
elevator.Request.getTime() | 1.0 | 1.0 | 1.0 |
elevator.Request.Request() | 1.0 | 1.0 | 1.0 |
elevator.Request.Request(long) | 1.0 | 1.0 | 1.0 |
elevator.Request.sameAs(Request) | 1.0 | 1.0 | 1.0 |
elevator.Request.setAns(String) | 1.0 | 1.0 | 1.0 |
elevator.RequestHandler.handle() | 1.0 | 8.0 | 8.0 |
elevator.RequestHandler.move(Request,Elevator) | 1.0 | 1.0 | 1.0 |
elevator.RequestHandler.RequestHandler() | 1.0 | 1.0 | 1.0 |
elevator.RequestHandler.RequestHandler(Vector) | 1.0 | 1.0 | 1.0 |
elevator.RequestQueue.front() | 1.0 | 1.0 | 1.0 |
elevator.RequestQueue.isEmpty() | 1.0 | 1.0 | 1.0 |
elevator.RequestQueue.pop() | 1.0 | 1.0 | 1.0 |
elevator.RequestQueue.push(Request) | 3.0 | 3.0 | 3.0 |
elevator.RequestQueue.RequestQueue() | 1.0 | 1.0 | 1.0 |
Total | 70.0 | 83.0 | 99.0 |
Average | 1.5555555555555556 | 1.8444444444444446 | 2.2 |
Class metrics | ||
class | OCavg | WMC |
elevator.Elevator | 2.25 | 9.0 |
elevator.ElevatorRequest | 1.25 | 5.0 |
elevator.Floor | 1.0 | 5.0 |
elevator.FloorRequest | 1.25 | 5.0 |
elevator.Main | 6.0 | 6.0 |
elevator.Processor | 8.0 | 24.0 |
elevator.Queue | 1.25 | 10.0 |
elevator.Request | 1.0 | 7.0 |
elevator.RequestHandler | 2.25 | 9.0 |
elevator.RequestQueue | 1.4 | 7.0 |
Total | 87.0 | |
Average | 1.9333333333333333 | 8.7 |
Package metrics | ||
package | v(G)avg | v(G)tot |
elevator | 2.2 | 99.0 |
第三次作业
类图
- 优点:对上一次作业继承较好
- 缺点:有一个没有用的空类 Floor
度量
Method metrics | |||
method | ev(G) | iv(G) | v(G) |
smartelevator.SmartRequestHandler.SmartRequestHandler(Vector) | 1.0 | 1.0 | 1.0 |
smartelevator.SmartRequestHandler.SmartRequestHandler() | 1.0 | 1.0 | 1.0 |
smartelevator.SmartRequestHandler.modifyTimes(boolean,FenwickTree,int,int) | 1.0 | 7.0 | 7.0 |
smartelevator.SmartRequestHandler.isOnWay(int,int,int,Request) | 2.0 | 4.0 | 7.0 |
smartelevator.SmartRequestHandler.handle() | 12.0 | 35.0 | 48.0 |
smartelevator.SmartRequestHandler.checkSame(Queue<pair>,int,FenwickTree,Request) | 4.0 | 6.0 | 6.0 |
smartelevator.RequestQueue.RequestQueue() | 1.0 | 1.0 | 1.0 |
smartelevator.RequestQueue.push(Request) | 3.0 | 3.0 | 3.0 |
smartelevator.RequestQueue.pop() | 1.0 | 1.0 | 1.0 |
smartelevator.RequestQueue.isEmpty() | 1.0 | 1.0 | 1.0 |
smartelevator.RequestQueue.front() | 1.0 | 1.0 | 1.0 |
smartelevator.RequestQueue.clear() | 1.0 | 1.0 | 1.0 |
smartelevator.RequestHandler.RequestHandler(Vector) | 1.0 | 1.0 | 1.0 |
smartelevator.RequestHandler.RequestHandler() | 1.0 | 1.0 | 1.0 |
smartelevator.RequestHandler.move(Request,Elevator) | 1.0 | 1.0 | 1.0 |
smartelevator.RequestHandler.handle() | 1.0 | 8.0 | 8.0 |
smartelevator.RequestHandler.getRequests() | 1.0 | 1.0 | 1.0 |
smartelevator.Request.setAns(String) | 1.0 | 1.0 | 1.0 |
smartelevator.Request.sameAs(Request) | 1.0 | 1.0 | 1.0 |
smartelevator.Request.Request(long,String) | 1.0 | 1.0 | 1.0 |
smartelevator.Request.Request() | 1.0 | 1.0 | 1.0 |
smartelevator.Request.getTime() | 1.0 | 1.0 | 1.0 |
smartelevator.Request.getInput() | 1.0 | 1.0 | 1.0 |
smartelevator.Request.getFloor() | 1.0 | 1.0 | 1.0 |
smartelevator.Request.getAns() | 1.0 | 1.0 | 1.0 |
smartelevator.Queue.resize() | 1.0 | 1.0 | 2.0 |
smartelevator.Queue.Queue() | 1.0 | 1.0 | 1.0 |
smartelevator.Queue.push(E) | 1.0 | 2.0 | 2.0 |
smartelevator.Queue.pop() | 1.0 | 1.0 | 1.0 |
smartelevator.Queue.length() | 1.0 | 1.0 | 1.0 |
smartelevator.Queue.isEmpty() | 1.0 | 1.0 | 1.0 |
smartelevator.Queue.front() | 1.0 | 1.0 | 1.0 |
smartelevator.Queue.elementAt(int) | 1.0 | 1.0 | 1.0 |
smartelevator.Queue.clear() | 1.0 | 1.0 | 1.0 |
smartelevator.Pair.setSecond(int) | 1.0 | 1.0 | 1.0 |
smartelevator.Pair.setFirst(T) | 1.0 | 1.0 | 1.0 |
smartelevator.Pair.Pair(T,int) | 1.0 | 1.0 | 1.0 |
smartelevator.Pair.Pair() | 1.0 | 1.0 | 1.0 |
smartelevator.Pair.getSecond() | 1.0 | 1.0 | 1.0 |
smartelevator.Pair.getFirst() | 1.0 | 1.0 | 1.0 |
smartelevator.Main.main(String[]) | 3.0 | 7.0 | 7.0 |
smartelevator.InputProcessor.process(int) | 24.0 | 24.0 | 31.0 |
smartelevator.InputProcessor.printIllegalRequest(String) | 1.0 | 1.0 | 1.0 |
smartelevator.InputProcessor.InputProcessor(String) | 1.0 | 1.0 | 1.0 |
smartelevator.InputProcessor.InputProcessor() | 1.0 | 1.0 | 1.0 |
smartelevator.FloorRequest.sameAs(Request) | 2.0 | 1.0 | 3.0 |
smartelevator.FloorRequest.getFloor() | 1.0 | 1.0 | 1.0 |
smartelevator.FloorRequest.getDirection() | 1.0 | 1.0 | 1.0 |
smartelevator.FloorRequest.FloorRequest(int,int,long,String) | 1.0 | 1.0 | 1.0 |
smartelevator.FloorRequest.FloorRequest() | 1.0 | 1.0 | 1.0 |
smartelevator.FenwickTree.query(int) | 1.0 | 1.0 | 2.0 |
smartelevator.FenwickTree.getSize() | 1.0 | 1.0 | 1.0 |
smartelevator.FenwickTree.FenwickTree(long[]) | 1.0 | 2.0 | 2.0 |
smartelevator.FenwickTree.FenwickTree() | 1.0 | 1.0 | 1.0 |
smartelevator.FenwickTree.add(int,long) | 1.0 | 1.0 | 2.0 |
smartelevator.FenwickTree.add(int,int,long) | 1.0 | 3.0 | 3.0 |
smartelevator.ElevatorRequest.sameAs(Request) | 2.0 | 1.0 | 2.0 |
smartelevator.ElevatorRequest.getFloor() | 1.0 | 1.0 | 1.0 |
smartelevator.ElevatorRequest.ElevatorRequest(int,long,String) | 1.0 | 1.0 | 1.0 |
smartelevator.ElevatorRequest.ElevatorRequest() | 1.0 | 1.0 | 1.0 |
smartelevator.Elevator.waitUntil(long) | 1.0 | 1.0 | 1.0 |
smartelevator.Elevator.toString() | 1.0 | 1.0 | 1.0 |
smartelevator.Elevator.move(int) | 1.0 | 1.0 | 6.0 |
smartelevator.Elevator.getTime() | 1.0 | 1.0 | 1.0 |
smartelevator.Elevator.getFloor() | 1.0 | 1.0 | 1.0 |
smartelevator.Elevator.Elevator() | 1.0 | 1.0 | 1.0 |
Total | 110.0 | 156.0 | 190.0 |
Average | 1.6666666666666667 | 2.3636363636363638 | 2.878787878787879 |
Class metrics | ||
class | OCavg | WMC |
smartelevator.Elevator | 1.8333333333333333 | 11.0 |
smartelevator.ElevatorRequest | 1.25 | 5.0 |
smartelevator.FenwickTree | 1.8333333333333333 | 11.0 |
smartelevator.Floor | 0.0 | |
smartelevator.FloorRequest | 1.2 | 6.0 |
smartelevator.InputProcessor | 6.75 | 27.0 |
smartelevator.Main | 6.0 | 6.0 |
smartelevator.Pair | 1.0 | 6.0 |
smartelevator.Queue | 1.2222222222222223 | 11.0 |
smartelevator.Request | 1.0 | 8.0 |
smartelevator.RequestHandler | 2.0 | 10.0 |
smartelevator.RequestQueue | 1.3333333333333333 | 8.0 |
smartelevator.SmartRequestHandler | 7.0 | 56.0 |
Total | 165.0 | |
Average | 2.426470588235294 | 12.692307692307692 |
Package metrics | ||
package | v(G)avg | v(G)tot |
smartelevator | 2.878787878787879 | 190.0 |
Bug分析
这几次作业我基本没有出过什么大的问题,第二次作业我将 $100$ 条指令的边界判成了 $101$ 条,第三次作业当指令合法时我忘记了在输出中去掉空格。这反映出我在处理输入、输出的时候还不够细心,测试构造还不够完善,今后需要进一步努力。
测试策略
这几次作业,我的测试方法主要有两种:
- 阅读源代码,寻找其中的错误。例如,第一次作业中,我发现我抽到的代码对于 $20$ 个多项式的边界判断有误,用错了 $>$ 和 $ge$,导致 $21$ 个多项式时仍会被判为合法。找到错误以后,构造测试数据就非常简单了。
- 使用自动化测试,随机大量的测试数据来找到被测代码的错误。例如第二次作业中,我就通过自动化测试发现了对方几个调度上的错误,包括没有正确地判断同质请求等。
心得体会
通过这几次 OO 作业,我学到了不少东西。虽然之前学习过一些 java 的皮毛,但是基本上没有认真地写过几行代码,而现在我已经较为熟练地掌握了 java 这门语言。
对于面向对象的理解和相应的设计,由于我之前有一定的编写 c++ 的经验,在这方面没有遇到太大的困难。当然,c++ 和 java 在语言特性上稍有一些不同,使用起来需要适应。
同时,这几次作业也反映出我做一些事情的时候较为粗心,对于各种边界以及格式的检查总是会出现一些错误或者遗漏。这些问题本来可以通过仔细阅读代码或者构造测试数据来解决,但是我既没有仔细地去读代码,也没有细心地构造数据(例如第三次作业的格式测试数据是直接用的第二次的测试数据,这才导致没删空格的问题没有被发现)。这方面的问题需要之后更加细心地处理。
总的来说,这几次作业我完成的质量还是比较好的,也有了很大的收获。今后我会在这门课程上继续努力,让自己更加充实。