2018-北航-面向对象-前三次OO作业分析与小结
基于度量的程序結構分析
由于平時使用了NetBrains出品的IDEA作為IDE,在分析程序的時候我使用了IDEA的插件Metrics Reloaded。然而在使用時發現不懂得很多分析項目的含義,因此花費了一些時間了解,并在這里總結。
Complexity Metrics(復雜度分析)
這部分我們需要使用的主要是方法和類的復雜度分析。
方法的復雜度分析主要基于循環復雜度的計算。循環復雜度是一種表示程序復雜度的軟件度量,由程序流程圖中的“基礎路徑”數量得來。
ev(G):即Essentail Complexity,用來表示一個方法的結構化程度,范圍在$[1,v(G)]$之間,值越大則程序的結構越“病態”,其計算過程和圖的“縮點”有關。
iv(G):即Design Complexity,用來表示一個方法和他所調用的其他方法的緊密程度,范圍也在$[1,v(G)]$之間,值越大聯系越緊密。
v(G):即循環復雜度,可以理解為窮盡程序流程每一條路徑所需要的試驗次數。
對于類,有OCavg和WMC兩個項目,分別代表類的方法的平均循環復雜度和總循環復雜度。
Dependency Metrics(依賴度分析)
依賴度分析度量了類之間的依賴程度。有如下幾種項目:
第一次作業
類圖如下:
這次作業比較簡單,當時也很很努力的用來OO思想。但從算法角度來說效率比較低。除了面向對象對象思想之外,還學習到了正則表達式和異常處理。
第二次作業
類圖和度量分析圖如下:
| "Building.Building(int,int)" | 1 | 1 | 1 |
| "Building.getMaxFloor()" | 1 | 1 | 1 |
| "Building.getMinFLoor()" | 1 | 1 | 1 |
| "ERequest.ERequest(int,double)" | 1 | 1 | 1 |
| "Elevator.Elevator(Building,double,double)" | 1 | 1 | 1 |
| "Elevator.getFinishTime(int,double)" | 1 | 1 | 1 |
| "Elevator.gotoFloor(int,double)" | 1 | 3 | 3 |
| "FRequest.FRequest(int,double,String)" | 1 | 1 | 2 |
| "FRequest.getDirection()" | 1 | 1 | 1 |
| "FRequest.isSame(Object)" | 2 | 1 | 2 |
| "Request.Request(int,double)" | 1 | 1 | 1 |
| "Request.getFloor()" | 1 | 1 | 1 |
| "Request.getTime()" | 1 | 1 | 1 |
| "Request.isIllegal(int,double,Building)" | 1 | 3 | 3 |
| "Request.isSame(Object)" | 4 | 1 | 4 |
| "Request.parse(String,Building)" | 5 | 3 | 5 |
| "RequestQueue.RequestQueue(Building)" | 1 | 1 | 1 |
| "RequestQueue.finishRequest()" | 1 | 1 | 1 |
| "RequestQueue.getRequest()" | 1 | 1 | 1 |
| "RequestQueue.inQueue(Request)" | 3 | 2 | 3 |
| "RequestQueue.isEmptyQueue()" | 1 | 1 | 1 |
| "RequestQueue.isIllegal(Request,double)" | 4 | 7 | 7 |
| "RequestQueue.readAll()" | 12 | 8 | 12 |
| "RequestQueue.updateNext()" | 1 | 1 | 1 |
| "RequestQueue.updateUntil(double)" | 1 | 4 | 4 |
| "Scheduler.Scheduler(Elevator,Building)" | 1 | 1 | 1 |
| "Scheduler.command()" | 1 | 3 | 3 |
| "Scheduler.main(String[])" | 1 | 1 | 1 |
由于程序本身比較簡短,度量工具看不出太多的問題。程序的耦合狀況還可以。主要是用于輸入的RequestQueue.readAll()的復雜度較高,可以通過將方法進行拆解,提高可讀性。
我將兩種請求繼承自一個Request父類,而在最近閱讀《Java核心技術》時,我發現可以在Request類中增加一個工廠方法來進行字符串的解析,而不是把字符串的解析放到請求類本身的構造函數中。
第三次作業
類圖和度量分析圖如下。
| ALS_Scheduler | 3.5 | 21 | 0 | 10 | 10 | 0 | 0 |
| Building | 1 | 3 | 0 | 0 | 0 | 5 | 8 |
| ERequest | 1 | 2 | 2 | 1 | 5 | 2 | 7 |
| Elevator | 1.75 | 21 | 0 | 4 | 6 | 3 | 4 |
| FRequest | 1.5 | 6 | 2 | 3 | 5 | 3 | 7 |
| HitchHikerQueue | 2.22 | 20 | 0 | 5 | 9 | 1 | 1 |
| Movable.Direction | n/a | 0 | 0 | 0 | 0 | 5 | 8 |
| Request | 1.88 | 15 | 2 | 3 | 5 | 7 | 7 |
| RequestQueue | 2.25 | 27 | 1 | 3 | 8 | 3 | 3 |
| Scheduler | 2.5 | 10 | 1 | 6 | 8 | 2 | 3 |
限于篇幅沒有給出方法的度量,但是可以發現復雜度較高的方法有HitchHikerQueue.getNextFloor(),RequestQueue.readAll(),ALS_Scheduler.isHitchHikable()。這三個方法的作用分別是得到在考慮捎帶請求的情況下的下一個停留樓層,讀入所有請求,以及判斷當前請求是否可以被捎帶。其中讀入請求的方法不可避免,而另外兩個方法則由實現方法導致。不過仔細檢查之后確實發現了getNextFloor()方法可以簡化的地方。
這次作業的思路是由請求隊列RequestQueue讀入和保存當前正在等待的請求,增加一個HitchHikerQueue類保存正被捎帶的類,電梯類Elevator則保存了當前運動信息,具有有輸出功能,Scheduler負責調度。
這次作業的設計基本延續上次的思路,為了努力達到OO思想(實際上是偷懶符合符合直觀),我設計了等待請求隊列,捎帶請求隊列和帶有所有運動信息和輸出功能的電梯。但這樣也給我帶來了很多麻煩。原因如下:
互測部分
說實話,三次作業拿到的代碼都不算太好,還是比較面向過程的。三位同學都采用了一個個掃字符串處理輸入而不是正則表達式反向匹配,而且在之后電梯的代碼量又較大,讓我很難把代碼讀進去。
因此,在測試過程中,我主要是把自己的測試數據或者對拍來找出對方的錯誤,然后調試程序找到錯誤點,找到原因并進一步發掘更多的錯誤點。
第一次作業
對方:第一位同學主要出錯在數據處理上,比較原始的字符串處理方式難免的弊端。
我方:這次作業是我唯一被測出問題的一次,問題在于對指導書的理解有問題。我將指導書所說的不輸出零項理解為了不輸出次數為0的項,從而造成錯誤。
第二次作業
對方:第二位同學則是由于INVALID格式的問題,錯誤樹上幾乎被掛滿。但我還是找出了一些邊界條件上處理的錯誤,這位同學把關門時刻的請求當做了非同質請求,十分可惜。另外,他的輸入在某些情況下會導致指針越界,是使用原始數組的弊端了。
我方:這次沒有被測出Bug
第三次作業
對方:第三位同學在我一系列時間的對拍后都未出現錯誤,倒是代碼中通過以0.5s為粒度的模擬方式比較有意思。雖然比較低效,但是使得程序難以出錯。
我方:這次沒有被測出錯誤
總結
這三次作業中,我對第三次作業比較不滿意。一是因為開始寫代碼之前沒有想清楚,造成后來拆東墻補西墻。另外這次作業還是有一些算法的意思在里面,以我的實現方法,就需要一個高效的數據結構,然而當時只是為了讓程序跑起來,并沒有想太多。
轉載于:https://www.cnblogs.com/qianmianyu/p/8698557.html
總結
以上是生活随笔為你收集整理的2018-北航-面向对象-前三次OO作业分析与小结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 打造万能的Python开发环境
- 下一篇: linq之多表连接