面向對象課程第一次隨筆

1、基於度量分析程序結構編程

第一次做業數組

第二次做業架構

第三次做業函數

類圖(以第三次做業爲例)工具

 

 

這學期進行oo課程以前,我並無接觸過面向對象的編程方法,從以上第一次課程做業能夠看出,我在對類的設計依然是過程式的思惟,只是將傳統的過程式變成劃分爲了多個類,而將每一個類的方法簡單的看做實現整個程序的函數。因爲第一次做業較爲簡單,我並無所以而產生許多bug,但本身這樣設計是違反面向對象的編程思想的。學習

第二次做業和第三次做業都是電梯,區別在與調度策略不一樣。吸收了上次的經驗教訓,個人設計流程以下測試

(1)劃分類,例如電梯類,樓層類,調度器類等。spa

(2)思考每一個類要實現的功能設計

(3)肯定每一個類的方法和屬性調試

(4)肯定每一個類之間的協做關係

這樣設計,以對象做爲設計單位,每一個對象內的屬性所有爲private。代碼的結構比較清晰,勉勉強強算一個面向對象程序吧。寫代碼過程當中,我發現,這樣寫代碼比較容易維護和查找bug,實現對代碼的分塊管理。

在第三次做業中,引入了繼承和接口的面向對象基本概念,我雖然按照課程設計的要求進行了使用,可是因爲第三次做業基於第二次做業的基礎上修改,個人設計出現了很大的問題。

 該次做業在第二次做業的基礎上對調度器類進行繼承Dispatcher->NewDispatcher(Schedule),並利用接口的來概括電梯的運動狀態。我在繼承調度器類的時候,並無想好怎麼設計新的調度規則。我重載了本身的dispatch方法,也就是調度方法,在第二次做業中,該方法就略顯複雜,這一次直接致使該方法複雜度爆炸,而且出現了許多bug,險些致使筆者的此次做業failed。

注:能夠看出該方法的圈複雜度高到恐怖

 整體來講,對第三次做業來講,個人做業因爲沒有很好地規劃新的調度邏輯,致使了某些方法和類承擔了過多本不應本身承擔的任務。

2、Bug分析

第一次做業 

無bug被查出,本身最開始寫的時候不會正則卻是出了很多bug

第二次做業

(1)錯誤分支:忽略不一樣時的同質請求

在進行程序設計時,我在樓層類內有一個數組,記錄在有樓層請求時,該數組記錄電梯到達該樓層的時間。可是在考慮同質請求時,會用到該數組記錄的時間。可是,樓層的同質請求是區分上行鍵和下行鍵的。單純經過這個時間來判斷實際上忽略了上行和下行,致使了bug。

bug位置:Floor類

第三次做業

(1)錯誤分支 :WFS狀態,不捎帶

錯誤是因爲我在進行時間計算時,在輸出爲still狀態時將開關門算了兩次,很是不細心致使的bug,在課下的測試中意外的沒有被發現。

bug位置:電梯類,run方法

(2)錯誤分支:主請求選取順序

錯誤是因爲我在進行選取下一個主請求的方法中有一個循環,我在寫這個循環時失誤將循環的初始值做爲了循環變量,很是蠢。

bug位置:NewDispatcher類,dispatch方法

(3)錯誤分支:請求完成時間

致使錯誤緣由有二,一是由於錯誤分支(1)中的緣由,二是由於我在判斷捎帶和同質時,是先判斷捎帶,再判斷同質。這樣判斷,在大部分的狀況下,同質指令依然會被正確檢測,可是當兩條指令同質而前一條做爲主指令,後一條不會被捎帶時,會致使同質請求判斷錯誤。

bug位置:NewDispatcher類,dispatch方法

從問題不少的第三次做業來看,包括我在課下測試調試中發現的問題,大部分問題發生在dispatch方法中和該方法與電梯類協調時,可見講一個類的功能特別複雜,就容易致使管理麻煩,並且出現bug。合理劃分功能給各個類與方法能夠必定程度上避免這些問題。(筆者已經準備將第三次代碼重構了)

3、測試中的策略

(1)查看錯誤分支樹

錯誤分支樹基本涵蓋了咱們可能出現的bug,我首先根據錯誤分支樹,對每一個分支構造較小的數據。

(2)利用C代碼去 構造較大的數據去測試

大一些的數據可能會覆蓋到小數據覆蓋不到的各類狀況。

(3)閱讀測試程序代碼並分析結構

這一點我作的很差,在測試時去檢查一份和我的思路不一樣的代碼是十分困難的,我的讀完一遍除非是明顯的漏洞,能力所限,很難讀出bug。因此常常根據以上兩條來進行測試。

在此次寫博客分析代碼結構的過程當中,我發現經過metrics等工具分析代碼結構也是不錯的選擇。我自身的bug每每出如今迭代次數多,代碼長度長,圈複雜度高的區域,利用這點來尋找代碼的脆弱部分應該也是可行的。

4、心得體會

(1)這門課以前,我沒有寫過任何面向對象的程序。接觸了面向對象後,至關於多了一種看待程序設計的方式。一樣是從想要的結果出發,曾經我寫的過程式程序,考慮最多的是有什麼函數,實現什麼功能,經過怎樣的的流程來完成一個程序。而面向對象的程序設計方法,是從程序要實現的功能入手,將程序由流程變爲各個對象之間的交互(我的理解)

(2)多考慮一些狀況,永遠也不要讓你的程序crash。做爲寫程序的人,咱們須要對本身的程序負責,採起措施防止它破壞。

(3)程序不是從頭寫到尾,先構思好設計好,才能減小修改次數,少出bug。這一點在去年的計組課上我就深有體會,然而面向對象課的不一樣在於,沒有人會指導你如何設計,你須要本身構思本身的代碼架構,這對我來講並不容易。

(4)曾經我覺得,我會花不少心思在找別人的bug上,如今我發現,大部分時間都在敲本身的代碼,測試本身的程序。幫助他人測試的過程,對我來講,更像是學習大佬的設計。一些同窗的程序讓我從中學習到了很多東西(正則怎麼寫,怎麼設計方法)。

 

 

PS:一點補充,關於圈複雜度與bug的產生

「圈複雜度(Cyclomatic Complexity)是一種代碼複雜度的衡量標準。它能夠用來衡量一個模塊斷定結構的複雜程度,數量上表現爲獨立現行路徑條數,也可理解爲覆蓋全部的可能狀況最少使用的測試用例數。圈複雜度大說明程序代碼的判斷邏輯複雜,可能質量低且難於測試和維護。程序的可能錯誤和高的圈複雜度有着很大關係。」

簡單來說,圈複雜度越大表明你的程序要測試的可能性越多,代碼越難以維護。

圈複雜度計算公式 V(G) = e - n + 2。e表明程序流程圖中的邊數,n表明節點數。

舉例計算在網上能夠自行查看,在這裏很少贅述。

基本上來講,若是你使用很是多的if.....else語句,那麼圈複雜度會比較高。

拿第三次做業中個人一段出現bug的代碼爲例

if((requesttake[k].getFR()<=aim_floor && direct == 0)||(requesttake[k].getFR()>=aim_floor && direct == 1)) {
                    taking = true;
                    if(((requesttake[k].getFR()==aim_floor && direct == 0)||(requesttake[k].getFR()==aim_floor && direct == 1))&& requesttake[k].gettime()>=requestlist[main].gettime()){
                        if(requesttake[k].gettime()==requestlist[main].gettime()) {
                            if(requesttake[k].getplace()>requestlist[main].getplace()) {
                                break;
                            }
                        }
                        else {
                            break;
                        }
                    }
                    if(run(requesttake,k)==1) {
                        requestlist[requesttake[k].getplace()].changeiftake(true);
                        k++;
                        if(origin_floor != elevator.floor()) {
                            i++;
                        }
                        origin_floor = elevator.floor();
                    }
       }

顯然這段代碼很是很差,很是多的if..else就像這樣

很難覆蓋化測試並且很是容易出現bug。

此外,個人一個很差的習慣也是致使這段代碼變成這個樣子的緣由。第三次做業中出現的bug,每每是來源於有些狀況沒有考慮或者現有機制處理錯誤。我常常在此基礎上加入簡單的條件語句來使bug變爲一種特殊狀況,修正bug。這樣帶來的後果就是原本代碼脆弱的部分就愈來愈臃腫,愈來愈難以維護,圈複雜度提高,總體的方差也上升很快。

望引覺得戒。

相關文章
相關標籤/搜索