BUAA_OO_2020_第一單元總結


BUAA_OO_2020_第一單元總結

OO第一單元作業主題為表達式求導,主要學習目標為熟悉面向對象思想,學會使用來管理數據,感受分工協作的行為設計,建立程序魯棒性概念。如今,第一單元的學習已落下帷幕,再次對於本人的學習心得和成果進行總結。

第一次作業

基於度量的代碼結構分析

第一次作業為簡單表達式求導,不涉及因子、嵌套等復雜結構,因此代碼結構相對簡單。UML類圖如下:

  • 架構

    第一次作業我分了三個類,即主函數類、表達式類和項類。主函數類中只有Main函數,進行讀取輸入、創建表達式等功能。表達式類中含有存儲項的HashMap用於存儲表達式的所有項,還有ArrayList用於存儲求導過后的所有項。

  • 函數調用

    在表達式類中含有求導函數,主類調用該函數后,會觸發表達式中各個項調用自身的求導函數。同理,在主類調用表達式類中的print函數時,也會觸發各個項調用自身的printItem函數。

經過寒假pre的學習,我已經初步建立了面向對象的思想,並在這次作業中加以運用,初步實現了每個類各做各事的獨立性。

從代碼復雜度分析數據可以看到,各個方法的圈復雜度、模塊設計復雜度都在合理范圍之內,唯有項類中getPrintNum函數的基本復雜度較高。經分析,這是因為該方法的if-else語句缺少else部分,導致選擇結構不完整。三個類的LCOM(內聚缺乏度)值和各方法的iv(G)都較低,說明代碼基本符合高內聚低耦合的設計標准。

關於測評

本次作業沒有在中測、強測和互測中出現bug。

在互測時,共找到一個bug。有位同學在 + - 同時出現時會出現輸出符號錯誤的問題。經排查,是項前的符號與常數省略后的符號處理不到位導致。可見,在對於輸入表達式進行正規化和正則表達式匹配上,需要細心分析輸入的形式化描述,防止理解出現偏差。

由於這次作業內容較少,沒有過多bug出現。

 

第二次作業

基於度量的代碼結構分析

第二次作業在第一次的基礎上增加了三角函數,並且增加了因子概念,即可以存在多個因子相乘的項。同時,首次引入WrongFormat判定要求。首先,代碼核心部分UML類圖如下:

 

 

 

全部代碼UML類圖如下:

  • 架構

    在本次作業中,我新增抽象類Factor,即因子類。常數因子、冪函數因子、三角函數因子都繼承於Factor類。與第一次作業類似,Poly類中有存放Item的容器,而Item中也有存放Factor的容器。讀入表達式后,通過正則匹配出項,隨后引入工廠模式,講解析出的因子傳入工廠中,返回對應的因子。

  • 函數調用

    在進行求導、打印結果操作使,由主函數觸發Poly類的對應方法,Poly遍歷各個Item后觸發Item的對應方法,Item觸發Factor的對應方法,實現層層向下,各做各事的設計。

  • 解析

    另外,為了方便正則表達式的使用,專門設置一個正則表達式類,存放各類因子、項的正則表達式。在解析正則表達式時,采用層層向下的方法。先寫出因子的表達式,再組合為項,思路會更加清晰。由於本次作業不涉及空白符導致的WF,因此我采用先去空白符,再將正則表達式匹配的項全部取出來,拼接成一個字符串,與原有字符串進行對比。如果不同,則WF的方法,規避了分類討論。

  • 性能

    我使用的化簡方法為:對當前的表達式進行dfs,每次遍歷每兩項,如果滿足以下化簡條件的任意一個,則進行相應的合並,並將合並后的再次dfs。如果合並后表達式長度短於當前,則更新。

     asin**2F + bcos**2F
     aF + bsin**2F
     aF + bcos**2F
     asin**4F - bcos**4F

     

     

     

從代碼復雜度分析數據可以看出,Item類simplify函數復雜度整體偏高,圈復雜度、基本復雜度和模塊設計復雜度均超標。經分析,主要由於其對因子進行合並同類因子的化簡操作,需要排查因子各個參數,導致復雜度由明顯提升。Poly類用於化簡三角函數的dfs函數圈復雜度較高,是由於三角函數化簡情況過多,分支過多造成。

從類的層面看,Poly類由於和Item類的關聯過高,導致LCOM值過高,內聚性不良。

從關聯矩陣來看,Item類和Factor類的管理度明顯高,是由於Item類需要管理Factor的生成、求導、打印等全部步驟。本次作業由於沒有嵌套,沒有出現循環依賴情況。

總體來看,本次代碼復雜度相對良好,主要問題都出在三角函數的化簡步驟上。如需改良代碼,需要簡化化簡步驟,尋求更簡略的化簡方法。

另外,在進行本次作業設計時,應考慮到第三次作業的可擴展性問題,因此采用了此層次化的架構。

 

關於測評

本次作業沒有在中測和互測中出現bug,在強測中TLE了一個點。出錯原因為錯判dfs函數RE和TLE到來的先后順序,將三角函數化簡的dfs層數限制過大,導致還未到強制跳出階段就已經到達程序限定執行時間。改進方法為增加測定函數執行時間函數,當當前執行時間達到1900ms時,強制跳出dfs

在互測中,找到兩個bug。一位同學在化簡過程中,對cos(x)進行求導后沒有乘sin(x)導致錯誤。另一位同學在+x和-x多次重復出現時出現漏算現象。總結來看,兩位同學的出現的錯誤都是在多重組合下出現的問題,即多種情況重疊才會出現。這體現出,當程序復雜度較高時,很有可能由於細節疏漏,導致多種情況重疊時出現bug。

 

第三次作業

基於度量的代碼結構分析

本次作業在前兩次的基礎上增加了表達式因子、三角函數嵌套即空白符導致的WF。使得作業的難度有所上升。主要部分UML類圖如下:

 

 

全部結構的UML類圖如下:

  • 整體架構

    由於在第二次作業時考慮到第三次作業的擴展問題,因此代碼的大體架構並沒有改動。由於增加了表達式因子,因此將Poly類也繼承於Factor抽象類,並且可以通過FactorFactory進行工廠方法的解析。另外,由於增加嵌套,在三角函數類中增加一個屬性:Factor類的因子。

  • 表達式解析

    由於本次作業存在嵌套,難以用正則表達式直接解析。我采用的是邊解析邊下沉的方法。拿到表達式后,首先對其正規化(將**替換為^, \t替換為空格等),方便以后的解析。在表達式類中,解析出各個項,處理表達式層面的WF情況(如空串、括號數量不對稱等),並將字符串傳入項中。在Item類中,解析出各個因子,處理項層面的WF情況(如符號數量錯誤),並將因子字符串傳入FactorFactory中解析出對應的因子類型。在工廠中,就可以根據正則表達式匹配不同類型的因子,並且返回一些因子層面的WF(如三角函數保留字錯誤、指數超范圍等)。

  • 函數調用

    求導和打印的函數調用結構與前兩次作業類似,由主函數觸發Poly的對應函數,進而下沉觸發Item的,以此類推,最終返回完整結果。

  • 性能

    本次作業性能分仍然占據相當的比重,化簡也是需要盡力而為的。然而,由於本次表達式結構復雜,化簡難度也有所提升。我本次作業將重點放在表達式的化簡(即合並同類項)上,而沒有着眼於像第二次作業一樣的三角函數化簡。對於嵌套的表達式因子,直接調用化簡函數合並同類項;對於求導過程中得到的項,可以在求導過程中合並。

 

 

可以看到,隨着作業結構的復雜度增加,代碼的復雜度也有明顯上升。本次作業復雜度超標的方法高達8個,其中,大部分類是延續第二次作業,復雜度提升的主要原因為增加了WF的判定,導致分支數明顯上升。項由於牽扯各個因子的方法調用,耦合度也較高。方法行數基本控制在50之內。

在類的層次,表達式類的內聚合度依然較小。

從關聯矩陣來看,表達式與項的關聯度、項與因子的關聯度依然很高,主要原因同第二次作業一樣。這次作業,由於出現嵌套情,因此出現了循環依賴情況,即三角函數類由工廠產生,而三角函數又要調用工廠解析內部嵌套的因子種類。

關於測評

本次作業在中測、互測、強測中沒有發現bug。

在互測中,共發現三個bug。

  • 一位同學在處理sin((0))*x的情況時出現RE,是由於對於空容器直接調用get所致。這類錯誤經常出現,因此要多加注意,在對容器進行取元素時,務必保證不越界。

  • 一位同學在處理多層嵌套,如(((((((x)))))))時,由於遞歸,會TLE。這反映的是代碼架構的問題,在起初進行設計時,就應該適當考慮代碼對於最壞情況的承受能力。

  • 一位同學在合並同類項時忘記考慮表達式因子不能合並為含有指數的形式,輸出(x)**2類似情況。這是由於研讀指導書不夠仔細造成的。對於要求較多的題目,首先應該仔細研讀指導書,提煉WF情況,不僅要又判別WF的能力,也要規避自己的輸出出現WF。

在我進行自我測試時,代碼出現的問題主要有以下幾點。

  • 同上述互測bug的第三個,我也出現在實現代碼過程中忽視了輸出不能WF的情況

  • 對於正負號的含義區分不明。本次作業中正負號共有三種性質:項前運算符、項首+1/-1省略、常數因子。若是僅靠符號數量和出現位置判斷,會十分繁瑣,而且容易判錯。應該采用規格化表達式、分割項、因子,並分層次判斷的方法,而不是在最頂層就全部處理。

 

發現bug策略

覆蓋性測試

在最初研讀指導書的時候,我就對指導書定義的所有可能出現的情況進行羅列,盡量覆蓋全部情況,得到最初版本的測試樣例。覆蓋包括且不僅包括:各因子單獨出現、組合出現、0特殊情況、WF等。

另外,在代碼構建階段,遇到較為復雜的分支結構時,我對於能走向各個分支的樣例進行枚舉,盡量做到覆蓋重要分支結構的每一種分支走向。

自動測評機

對於第2、3次作業,很多錯誤的出現都是多種情況疊加后產生的,很難通過手動構造發現,因此需要構建對拍機。我才用python腳本+批處理的方式,構建自動測評機。python負責自動生成樣例、正確答案計算、輸出答案計算,.bat用於對比輸出區別。

針對第三次作業,判定輸出不是WF也是測試的重點之一,因此采用將輸出結果再作為輸入,並判斷輸出的結果中是否有WF信息的方法。

 

工廠模式

從第二次作業開始,我就采用了工廠模式對於各類因子進行創建操作。首先,建立Factor抽象類,其中包含求導、打印方法。然后將常數因子、三角函數因子、冪函數因子、表達式因子繼承於Factor,並實現其中方法。

使用工廠模式可以使創建過程透明於用戶,並且對於項層次中遍歷處理Factor提供了很大的方便。

另外,工廠模式也具有良好的擴展性。當第二次作業的基本架構完成后,第三次作業只需要將表達式類也繼承於Factor,並實現其中方法即可。

 

心得體會

  • 寒假pre認真做很重要

    在寒假的兩次pre中,我初步建立了面向對象的設計思想,並了解了類、接口、繼承等基本概念,並且根據指導書的建議,初次去學習了工廠模式。研讀優秀同學代碼也讓我學到了很多更加優越的設計方式。這使得我在應對第一次作業時不會手足無措,更加從容。

  • 善用討論區很重要

    在三次作業的完成過程中,討論區的同學們為我解決問題的進度提供了巨大的幫助。包括以下幾點:

    • 抽象類和接口的比較,幫助我在第二次作業的架構上做出選擇

    • 自動測評機的構建,給予我構建對拍機的思路

    • 三角函數化簡的策略

    • x**2=x*x 的神仙優化

    • ...

    在此感謝同學們的熱心分享!

  • 可擴展性得早做准備

    重構雖好,但還是挺累人的,如果能提前考慮可擴展性,對后續工作的開展會有很大幫助。

  • 面向對象設計的優越性

    在完成作業過程中,我逐漸發現面向對象的設計成果確實比面向過程更加清晰,思路也更加結構化。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM