oo前三次作业总结

时间:2022-02-01 21:55:10

OO作业总结(1-3)


 

前言

这三次作业,是我第一次,真正的系统性接触和学习Java,在这三次作业中,我对Java的理解也逐渐加深,也逐渐领悟到了从C语言入门的我在应对工程代码方面的不足,这一次学习到的度量分析又为我打开了新的大门。


(一)代码的度量分析

(1)第一次作业

第一次作业,内容是多项式计算,其中并没有涉及到复杂的计算原理和程序逻辑,而是在输入和输出的处理上略有难度。对于当时不懂正则表达式的我来说,我的第一次作业使用了状态自动机。

在第一次作业中,分为3个类,Input类处理输入,Polynomial作为主类,Term类表示单个多项式。之前我一直觉得这份代码写得还算不错,直到我最近学习了Java代码的度量分析,才惊觉之前的代码有着诸多缺点。

接下来贴上分析结果截图

oo前三次作业总结

oo前三次作业总结

显然,我的循环复杂度Cyclomatic complexity)在Input类里过高了,也就是说我的Input类功能不够单一,做不到功能内聚,需要再划分为更小的模块,才能减小程序的漏洞数。

这次由于将状态机封装进了Input类,导致的Input类复杂度过高,以后的状态机或许可以分成多个简单类的交互。

(2)第二次作业

第二次作业,内容是傻瓜电梯的调度。虽然指导书刻意复杂化了代码逻辑,但其实代码非常之简单,只需要每次处理当前请求时,将请求队列之中的同质请求消除就可以了。

在这一次作业当中,我也意识到了try,catch的重要性,在面临可能数组越界或是访问空指针的危险情况时,try and catch变得尤为重要,这样可以快速帮助锁定错误所在,希望以后我也能像各位大牛一样将try catch运用熟练。

下面贴上类图和度量分析结果

oo前三次作业总结

oo前三次作业总结

oo前三次作业总结

本次代码设计上的主要问题从度量分析看来主要来自于Request类的SelfCheck方法,但是本人点进去仔细查看SelfCheck函数后却并不认为其有什么问题,代码如下:

1 boolean SelfCheck(double LastTime)
2 { 3 if(Time<LastTime)return false; 4 if(Type==0 && (Aim==0 || Aim>10))return false; 5 if(Type==1 && (Dep<=1 || Dep>10))return false; 6 if(Type==2 && (Dep==0 || Dep>9))return false; 7 if(Time>(1L<<32)-1)return false; 8 return true; 9 }

这个功能仅仅用来判断Request类是否合法,而由于限制条件的众多,代码内的众多if语句也难以避免,况且该功能十分明确且简单,个人不认为这段代码有不妥的地方。

以上就是这次分析的结果,个人认为这次的情况正好对应了*上所说的对于特殊情况,代码的循环复杂度可以酌情放宽

(3)第三次作业

关于第三次作业,我需要提前申明的是,本次作业我一开始的想法就错了,导致后面回天乏术。具体原因会在第二部分的bug互查说明,这里仅仅分析代码的性能。

下面贴上度量分析结果:

oo前三次作业总结

oo前三次作业总结

oo前三次作业总结

下面贴上Watcher中的FindDir作为示例:

 1     Request FindDir(double time)
 2  { 3 if(time==L.GetLast()+1 && L.IsOpen()) 4  { 5 //System.out.println("LastTime="+L.GetLast()+" time="+time); 6  L.Change(time); 7 //System.out.println(L); 8 if(Temp.GetFor()==0) 9  { 10 if(L.GetCnt(L.GetPos())>0 && L.GetReq(L.GetPos(), 1).GetAim()==L.GetPos()) 11  { 12 OUT.Add("VALID", 0, L.GetReq(L.GetPos(), 1), L.GetPos(), time); 13  L.pop(L.GetPos()); 14  } 15 if(F[L.GetPos()].GetQn()>0 && F[L.GetPos()].GUP(1).GetDep()==L.GetPos()) 16  { 17 //System.out.print("First:");F[L.GetPos()].GUP(1).Print(); 18 OUT.Add("VALID", 0, F[L.GetPos()].GUP(1), L.GetPos(), time); 19  F[L.GetPos()].PopQ(); 20  } 21 if(F[L.GetPos()].GetDn()>0 && F[L.GetPos()].GDN(1).GetDep()==L.GetPos()) 22  { 23 OUT.Add("VALID", 0, F[L.GetPos()].GDN(1), L.GetPos(), time); 24  F[L.GetPos()].PopD(); 25  } 26 while(L.GetCnt(L.GetPos())>0 && L.GetReq(L.GetPos(), 1).GetAim()==L.GetPos()) 27  { 28 OUT.Add("#SAME", 0, L.GetReq(L.GetPos(), 1), L.GetPos(), time); 29  L.pop(L.GetPos()); 30  } 31 while(F[L.GetPos()].GetQn()>0 && F[L.GetPos()].GUP(1).GetDep()==L.GetPos()) 32  { 33 OUT.Add("#SAME", 0, F[L.GetPos()].GUP(1), L.GetPos(), time); 34  F[L.GetPos()].PopQ(); 35  } 36 while(F[L.GetPos()].GetDn()>0 && F[L.GetPos()].GDN(1).GetDep()==L.GetPos()) 37  { 38 OUT.Add("#SAME", 0, F[L.GetPos()].GDN(1), L.GetPos(), time); 39  F[L.GetPos()].PopD(); 40  } 41  } 42  } 43 //System.out.println("haha="+L.GetAim()+" "+L.GetPos()+" "+L.IsOpen()+" time="+time+" last="+L.GetLast()); 44 //L.Print(time); 45 if(L.GetAim()==L.GetPos() && !L.IsOpen()) 46  { 47 //System.out.println("hahahahahahahhahaha"); 48 //L.Print(time); 49 50 //L.Print(time); 51 int aim1=0, aim2=0, aim3=0; 52 if(time==L.GetLast()) 53  { 54 int finish = L.Finish(); 55 if(finish!=0) 56  { 57 L.Direct(L.GetAim()-L.GetPos()==0 ? 0 : L.GetAim()-L.GetPos()==1 ? 1 : -1); 58 return new Request(-1); 59  } 60  } 61 //L.Print(time); 62 for(int i=1;i<=10;++i) 63  { 64 if(L.GetCnt(i)>0 && (aim1==0 || L.GetFront(i).GetSeq()<L.GetFront(aim1).GetSeq())) 65 aim1 = i; 66 if(F[i].GetQn()>0 && (aim2==0 || F[i].GUP(1).GetSeq()<F[aim2].GUP(1).GetSeq())) 67 aim2 = i; 68 if(F[i].GetDn()>0 && (aim3==0 || F[i].GDN(1).GetSeq()<F[aim3].GUP(1).GetSeq())) 69 aim3 = i; 70  } 71 if(aim1>0 && 72 (aim2==0 || (F[aim2].GetQn()>0 && L.GetFront(aim1).GetSeq()<F[aim2].GUP(1).GetSeq())) && 73 (aim3==0 || (F[aim3].GetDn()>0 && L.GetFront(aim1).GetSeq()<F[aim3].GDN(1).GetSeq()))) return L.GetFront(aim1); 74 if(aim2>0 && 75 (aim3==0 || (F[aim3].GetDn()>0 && F[aim2].GUP(1).GetSeq()<F[aim3].GDN(1).GetSeq())) && 76 (aim1==0 || (L.GetCnt(aim1)>0 && L.GetFront(aim1).GetSeq()>F[aim2].GUP(1).GetSeq()))) return F[aim2].GUP(1); 77 if(aim3>0 && 78 (aim2==0 || (F[aim2].GetQn()>0 && F[aim2].GUP(1).GetSeq()>F[aim3].GDN(1).GetSeq())) && 79 (aim1==0 || (L.GetCnt(aim1)>0 && L.GetFront(aim1).GetSeq()>F[aim3].GDN(1).GetSeq()))) return F[aim3].GDN(1); 80 return new Request(-1); 81  } 82 //L.Print(time); 83 return new Request(); 84 }

可见由于之前的逻辑分析失误,导致了if-else语句的滥用,由此可见,在写代码之前,有一个清晰,简单的框架是写好程序之必备,而本人在这一方面则反了经验不足的错误,以为简单按照描述来写就行,结果表明不成熟的程序框架会导致大量的冗余代码和复杂的·逻辑判断,今后必须引以为戒。


(二)bug分析

(1)第一次作业

第一次作业本人存在一个bug,那就是没有判断程序最开始是空格的情况。因为本人的最初版本程序要求程序第一个左括号,所以空格会导致判断为ERROR。

由此可见两个问题:

1.对内置函数不熟练,本来可以用string.replace来解决

2.逻辑思维不够严密

(2)第二次作业

第二次作业本人由于对助教意思的误解,对于同质请求没有输出#SAME,这是一个incomplete

(3)第三次作业

而第三次作业,本人为了完全再现电梯接受请求的反应,决定按照时间的运行来模拟,而这时由于一开始得考虑不周,本人犯了一些严重的错误:

1.电梯请求放在了电梯类,楼层请求放在了楼层类,导致交互时的代码非常繁琐

2.由于一开始的考虑不周,放弃了请求队列的想法,本意是想每次接受请求时只与当前请求比较,结果发现请求有可能排成队列

3.对于时间和请求的交互请求关系考虑不周,导致出现电梯没有及时改变方向,出现runtime error

综上所述,本人的第三次作业并没有达到理想要求,并非是修补bug可以解决的问题需要推倒重来。

以后也要吸取教训,对待程序一定要思考清楚后开始写,否则仅是浪费时间而已。