OO學習總結與體會

前言

  通過了對於面向對象程序設計的一個月的學習,我初嚐了JAVA以及面向對象程序的魅力。經歷了三次難度逐漸加大的課後編程做業,我對於工程化面向對象編程以及調試有了深入的認識與頗多感想。我寫下本篇文章以總結分析這一個月的課後做業的完成狀況。算法

 


 

 

做業總結與分析

多項式加減運算

 

(1)題目簡述:

  實現一元多項式的加減運算編程

 

(2)程序設計:

 

  Class設計:架構

  • PolyCul類:進行多項式輸入,多項式計算調度,多項式輸出。

 

  • Poly類:存儲多項式信息,進行多項式計算。

 

  • Item類:存儲單個項的信息,進行項的計算。

 

  程序規模:模塊化

  

 

  程序類圖與類演示圖:學習

  

  

(3)程序分析:

  程序的結構化程度(ev)、設計複雜度(lv)和斷定結構複雜度(v)狀況較好,只有負責輸入字符串合法性識別以及多項式組插入的方法的複雜度較高。其餘方法的複雜度都處於正常的範圍內。輸入字符串合法性識別方法複雜度高的緣由主要是最初設計時對於指導書的輸入需求的理解不夠充分,致使了一開始設計的識別算法沒法全面地處理輸入字符串,使得編程完成後要補充新的判斷分支,致使方法代碼冗餘。多項式組插入方法複雜度高的緣由是每次調用方法時須要遍歷已有的有序多項式組、判斷同次多項式、尋找新多項式在其中的位置擴展多項式組並插入新多項式。測試

  量化分析結果以下:優化

  

 

 

(4)出現的問題:

  Bug」-0」字符處理不當。this

  在最初的設計中並未考慮輸入」-0」的需求,處理這一需求的代碼是在程序完成後補充的。因爲補充代碼時僅考慮了處理」-0」,因此直接使用字符串替換將」-0」替換成了」+0」,致使了程序可以識別以」-0」爲前綴的數字,如」-001」。而負數輸入是非法的。spa

  從整個程序來看,該問題致使了程序內會存在非法的數值,雖然就指數計算來看負數引入並不會致使數學上的錯誤。但因爲程序內其餘的使用該變量的方法默認處理正數,而不存在處理負數的措施,對於輸入判斷模塊方法的正確性有必定的依賴性。出現入口的錯誤會使得程序存在崩潰的隱患。設計

  相關代碼:

private void str_input() {
        Scanner s = new Scanner(System.in);
        this.str = s.nextLine().replaceAll(" +", ""); //去除空格。
        this.str = str.replace("-0","+0");//去除-0.
        s.close();
    }

 

簡單電梯調度

(1)題目簡述:

  實現簡單(FAFS)電梯調度系統。

(2)程序設計:

  Class設計:

  Sheduler類:完成請求的輸入及處理,根據請求隊列調度電梯、輸出電梯運動狀況。

  ReqQueue類:實現對請求隊列內請求的處理,實現重複請求的識別與剔除。

  Request類:格式化存儲請求信息。

  Lift類:根據調度類改變電梯的位置、運動狀況以及電梯內各按鈕的狀態(未被使用)。

  Floor類:記錄每層樓按鈕的狀態(未被使用)。

 

  程序規模:

  

 

 

  程序類圖與類演示圖:

  

 

  

 

(3)程序分析:

  程序的結構化程度(ev)、設計複雜度(lv)和斷定結構複雜度(v)狀況通常。獲取下一執行請求的方法的複雜度最高,此外請求隊列遍歷操做的相關方法的複雜度也較高。在獲取下一執行請求的方法中須要對下一請求的同質性進行判斷,致使方法中存在大量的判斷語句的嵌套,產生了較多的判斷路徑。此外,判斷語句處於循環中,使得複雜度提升。出現這一狀況主要是因爲最初的設計不夠完善,在編程的過程當中不斷添加路徑,最後使判斷邏輯關係比較混亂,也就是模塊判斷複雜度的提升。其餘方法主要因爲非結構化代碼較多。

  量化分析部分結果以下:

  

 

  

 

(4)出現的問題:

  Bug:輸入數字範圍限制錯誤。

  指導書要求輸入數字範圍爲四字節,而程序中限制的是int型變量能表示的非負數。這主要是對於指導書的要求理解錯誤致使的。該錯誤對於程序正常運行的影響較小。

  Bug:」&」與」&&」運用錯誤。

  這一錯誤的表現形式是當輸入的請求存在同質請求時程序會崩潰。通過分析最後肯定了是如下代碼致使程序崩潰:

if(next_req.get_req_kind().equals("FR") & next_req.get_FR_operator().equals(running_req.get_FR_operator())) {
  next_req.set_fesibility(
false); System.out.println("#第" + next_req.get_input_line() + "個請求與第" + running_req.get_input_line() + "個請求行爲相同!"); continue; }

  該段代碼應當更改成:

if(next_req.get_req_kind().equals("FR") && next_req.get_FR_operator().equals(running_req.get_FR_operator())) {
    next_req.set_fesibility(false);
    System.out.println("#第" + next_req.get_input_line() + "個請求與第" + running_req.get_input_line() + "個請求行爲相同!");
    continue;
}

  「&&」與」&」的區別在於後者會對全部的表達式進行運算,最後取邏輯與獲得結果;而前者會順序對錶達式進行運算,若遇到了一個表達式爲false則不會對後面的表達式進行運算。而在上面代碼中,如第一個表達式爲false時,第二個表達式中的方法調用是非法的,若運行就會使程序崩潰。」|」和」||」的原理相同。

  這段代碼於程序的其餘部分的代碼相關性不高,只依賴於Request類的內部結構。電梯請求與樓層請求在格式上的不一樣使得該段代碼須要考慮兩者的特性與共性來產生判斷分支。出現這一問題主要因爲對於其特性的考慮不夠全面。

 

優化電梯調度

(1)題目簡述:

  實現具備捎帶功能的電梯調度系統。

(2)程序設計:

  Class設計:

  Sheduler類:實現簡單調度功能,爲前一做業的代碼。

  AlsSheduler類:完成請求的輸入及處理,根據請求隊列調度電梯、輸出電梯運動狀況。

  ReqQueue類:實現對請求隊列的基本處理。

  ExeQueue類:實現對執行請求隊列的基本處理。

  QueueHandleInterface接口:規範化請求隊列處理的方法。

  Request類:格式化存儲請求信息。

  Floor類:記錄每層樓按鈕的狀態(未被使用)。

  Lift類:根據調度類改變電梯的位置、運動狀況以及電梯內各按鈕的狀態(未被使用)。

  LiftInterface類:規範電梯類的接口。

 

  程序規模:

  

 

 

  程序類圖與類演示圖:

  

 

  

 

(3)程序分析:

  程序的結構化程度(ev)、設計複雜度(lv)和斷定結構複雜度(v)平均狀況通常,但有部分的複雜度至關高。其中主要是調度運行方法以及輸入處理的一系列方法。

  在調度運行方法中存在一個循環來模擬時間的流動,而且在每一時間幀中有大量條件判斷構建狀態機來實現電梯的調度。複雜的邏輯判斷致使這一方法的結構十分冗雜,加大了代碼的規模,大大提升了複雜度。出現這一問題的主要緣由是設計的調度算法未進行優化,較爲粗糙,在功能上未對代碼進行歸類,按照面向過程的思路堆砌判斷條件。

  在輸入處理方面,相較前兩次做業,本次做業的表現並很差。通過後期的分析,在這一部分出現了僞面向對象式的代碼。在相關的一系列方法中調用深度過深,實質上是將一個方法分割爲多個私有方法碎片,相互耦合的現象較嚴重。此外,在此次做業對上次做業進行繼承後發現輸入處理部分的代碼應當分離成單獨的類,而不該當歸屬於調度類。

  量化分析部分結果以下:

  

  

 

(4)出現的問題:

  在功能方面還沒有檢測出問題,但在程序結構的設計方面上暴露出了許多的缺陷。主要體如今:部分類的功能冗餘、調度算法須要優化、方法設計不穩當。


 

心得體會

  • 捕捉字裏行間的需求

  在這幾回的編程做業中,我最早感覺到的是充分理解需求的重要性。每一次做業都有一個篇幅較大較爲詳細的指導書。指導書對於程序需求與功能的描述或多或少有些模糊或者易產生歧義的地方,這對於程序的架構帶來了必定的困難。但相較於現實工做中遇到的客戶的需求描述,指導書中的描述已經具體了許多。而咱們所須要的就是從描述需求的天然語言之中提取出關鍵的信息,在零散的信息中尋找邏輯上的練習,並創建模型完成程序的架構

  在第一次做業中,需求的捕捉並不算太困難,主要在輸入合法性的判斷上。而在後兩次做業中,需求很明顯就複雜了許多。因爲指導書的篇幅較長,爲避免遺忘,我在通讀指導書的同時將發現的關鍵信息按條記錄下來。在屢次閱讀指導書後,我再將提取到的信息按照其所屬的功能部分進行分類,分析實現每一個需求所須要的代碼或算法。

  此外,在設計時還應當考慮到文中未說起的那些「言外之意」,使程序可以應對指導書中未說起的需求與輸入。這須要設計者對需求進行適當的外延與擴展,擴大程序的包容性、兼容性。這在現實的程序設計中具備至關重要的意義。

  • 結構設計模塊化

  面向對象編程最重要也是最困難的部分就是設計程序的結構:根據程序須要的操做和數據,將程序分離封裝成不一樣的功能模塊,每一個模塊的聚合度要高,各個模塊之間的交集要小。在設計程序時應當自頂向下地思考。若要實現總的需求,程序要具備哪些功能,須要擁有那些數據,須要對數據進行什麼操做?根據這些問題以及從指導書捕捉到的信息,咱們就可以大體地列出一個清單,再根據其中的聚合關係就能畫出程序的結構(類)圖。以後在優化的時候還可對設計進行微調,以得到分離度更好地類設計。

  在這三次做業中,我在程序結構設計上表現通常。在編寫的程序中已經有了聚合度比較好一些模塊,但在將程序建模成類圖後同推薦的設計比較仍是能發現許多的不足。我在輸入識別處理模塊的設計上就有失穩當:在這幾回做業中我都將這一模塊併入了調度模塊。這一設計並不符合模塊化設計的理念。輸入處理操做應當封裝成一個獨立的模塊專門進行相關的操做。而我將其併入調度類,就會使調度類過於繁雜,過於擴大其功能,提升了複雜度,下降了可維護性。從第三次做業繼承第二次做業時就能明顯感受到修改代碼的工做量較大。

  • 簡化方法規模

  在方法的設計上應當儘可能精簡每一個方法的代碼量,使每一個方法能高效地完成單一的一個任務。應當嚴格地控制每一個方法功能、判斷分支、調用深度和代碼規模對於下降程序的調試與維護難度有着不錯的效果。在我編寫的這幾個程序中,方法精簡的部分最容易進行修改,也最不容易出現問題;出現問題的地方主要是判斷分支較多的方法。

  要控制方法規模主要須要對程序中的各個操做進行準確的提煉,獲取其中核心的原子操做造成相應的方法。分析我程序中規模較大方法能夠發現,這些方法都包含了至少兩種操做,一個方法的功能過於繁雜。這樣就致使我維護、修改代碼時遇到了較多困難,而且容易產生不易發現的問題。

  • 系統化測試代碼

  因爲輸入狀況的多樣性,簡單的功能性測試是遠不夠的。按照老師課堂的要求,我在測試階段構建了錯誤分支樹。頂層按照正常功能與異常處理進行分叉,逐漸向下延伸產生錯誤分支,併爲每一個分支構造了一至兩個測試輸入。最後用構造的測試集進行代碼測試。經過這樣一個比較系統化的測試方式,我比較迅速準確地鎖定了存在問題的代碼。得益於結構化的代碼結構,我也可以較快地優化程序。

相關文章
相關標籤/搜索