1. 程式人生 > 其它 >BUAA_OO第一單元總結

BUAA_OO第一單元總結

第一單元作業總結

【注】以下所列出的思路、架構可能與實際提交作業有所區別,由於時間有限,實際提交程式碼的部分內容尚未完善。

1.第一次作業——單變數多項式的括號展開

1.1 設計思路

第一次作業作為第一單元的開山之作,難度適中,主要任務是對括號展開問題建立初步的認知,建立初版架構。

首先,這次作業涉及的物件有:

  • 帶符號整數:可能含有符號與前導零
  • 因子
    • 變數因子
      • 冪函式:分為一般形式與省略形式,
    • 常數因子:包含一個帶符號整數
    • 表示式因子:由小括號包裹且可能帶指數
  • 項:若干因子的乘積,第一個因子前可能額外帶有符號
  • 表示式:若干項的加減,第一項之前可能額外帶有符號

其次,我的總體處理流程為:
讀入表示式 → 處理第一個項 → 處理第一個因子 … → 處理第二個項 … → 處理最後一個項

為實現上述流程,我計劃定義五大類,其中含有一個Main類和一個抽象類,如圖所示。

Data類是資料型別的抽象類,其中的String以字串形式存取待處理的物件。
mapHashmap<Int, BigInt>型別,存取處理後的內容,Int型別的鍵為指數,BigInt型別的值為係數。
process為各物件的處理方法,通過呼叫該方法進入parse函式。
parseTermparseFac分別獲得下一個項及下一個因子。
處理因子時,首先通過type函式判斷該因子的型別,0為常數,1為冪函式,2為不帶指數的表示式因子,3為含指數的表示式因子。
之後通過一系列的dealCase方法對因子進行處理,將結果存至map

中。
由於此次作業運算不是很複雜,故沒有另外定義運算類,而是將運算過程融合進了處理方法。
在處理字串時,我使用了正則表示式的方法。
由於本次作業格式較為簡潔,通過正則表示式進行匹配非常高效,但是十分不利於擴充套件,因此也只有這次使用了正則。
處理完畢後,所有內容都儲存在了Poly類的map中,通過print方法輸出最終結果。

1.2 程式碼度量分析

整體來看,類的功能以及類之間的關係比較清晰。
但由於將字串處理和運算融合進了各類中,類的圈複雜度還是很高的。
尤其是parseTermprint方法明顯過於冗長,獨自一人承擔了太多,導致複雜度飆紅。

1.3 Bug

由於第一次作業難度適中,在強測與互測時都沒有被發現bug,且也沒有發現別人的bug。
但互測屋內有同學被找出了bug,主要與符號處理有關。對於-+-1

這樣的情況,很多同學直接採取字串替換的方法,雖然可以達到目標,但不夠靈活,在面對複雜情況時可能出現問題。

1.4 測試

構造測試用例的方法和作業思路類似,首先將因子分為若干類分別構造,再隨機選取若干種類型的因子構成項,再把若干項隨機組合為表示式。在構造資料時需要注意以下幾點:

  • 表示式不能巢狀,因此在構建表示式因子時需要避免遞迴
  • 數字部分需要考設計前導0
  • 項與因子前需要考慮設計額外的符號

1.5 小結

通過這次作業,成功建立起初步的架構,為後續的迭代開發提供基礎。同時訓練了面向物件的思維。但類的複雜程度仍然較高,在後續設計時應加以注意。

2.第二次作業——加入三角函式、自定義函式與求和函式

2.1 設計思路

本次作業的資料複雜度明顯增加,難度也隨之加大,主要表現為:

  • 新增三角函式:需要重新設計結果的存取與表示方法
  • 新增自定義函式:需要額外設計自定義函式類
  • 新增求和函式:需要額外設計求和函式類

處理流程為:

自定義函式預處理 → 讀入表示式 → 處理表達式(與第一次作業相同)

類圖為:

對於第一次作業中原有的類,只是在功能上作了擴充,總體結構為改變。
對於資料物件,新增了Sum類和Function類。它們與TermFactor等類的地位類似,只是在具體實現細節上有所不同。
此次新增了運算介面,AddMul類通過接受兩個列表分別進行加法和乘法運算。
這次作業,最重大的更新是新增了Tuple類,用以儲存項的結構。
一個項可由四部分組成:係數(含符號)、冪函式的指數、sin函式類、cos函式類。
對於前兩者,使用整數型別表示即可。對於後兩種,儘管本次作業只允許三角函式內出現常數因子與冪函式,但為了充分考慮可擴充套件性,決定使用ArrayList,其中的每一項存取的都是一個Poly型別的資料,這意味著三角函式內可支援任意型別的資料,實現了遞迴結構。
進行字串解析時,不再使用正則表示式,而是使用類似於文法分析的逐字元處理。

2.2 程式碼度量分析

本次程式碼複雜度依然很高。
具體檢視每一個方法,發現依然是parseTermparseFactor方法承擔了太多工作,
以及新增的addFunequalX方法繁瑣冗雜。
尤其是對於Function類,含有大量相似的程式碼,這些需要通過簡化設計進行優化。

2.3 Bug

同樣,本次作業在測試中沒有發現bug。但我在檢視他人的程式碼時發現了3處bug,它們都與三角函式的優化有關。
例如,試圖提取sin內的符號但處理錯誤、試圖化簡平方和但處理錯誤等等。
由此可見,這些同學在處理表達式時未被發現問題,反而是在優化效能時未注意到相關細節。
因此,不要一味地追求效能分而忽略了最基本的正確性,否則是得不償失。

2.4 測試

用例構造思路與第一次作業類似。對於新加入的自定義函式,可在滿足約束條件的前提下生成表示式,其中的自變數隨機從x,y,z中選擇。
對於求和函式,首先隨機生成上下界,再生成求和表示式,並把其中的randint(0,n)x更換為i

3.第三次作業——引入更多巢狀規則

3.1 設計思路

第三次作業沒有引入新的物件,但對可巢狀性進行了擴充。
由於在第二次作業時,我的架構已能支援各因子之間的巢狀,因此設計部分幾乎沒有進行改動。
針對輸出括號的要求,修改了PolytoString方法。當表示式只含有一個因子時不輸出括號,其餘情況輸出括號。
此外,針對性能優化完善了三角函式的化簡方法。

3.2 程式碼度量分析

通過分析程式碼的複雜度可知,此次作業較上次作業有一定程度的上升,而這主要是因為上述化簡方法。
由於三角函式的巢狀關係比較複雜,在判斷平方和等條件時需要較多的判斷條件,分支語句較多,邏輯較為複雜。

3.3 Bug

很不幸,此次作業我被測出了bug,在輸出括號的判斷條件上出現了問題,導致sin((-x))會輸出為sin(-x),而這主要是沒有認真審題導致的,充分說明了仔細閱讀指導書的重要意義,教訓深刻。
此次我也發現了別人的bug,同樣也出現在三角函式的化簡上,而且與我第二次作業發現的bug非常相似。可見三角函式的化簡不是一項簡單的任務,任何一處細節的缺失都有可能造成毀滅性的打擊。

3.4 測試:

測試用例的構造思路基本與第二次作業一致,只是放開了巢狀的限制。
由於我的架構可以支援任意組合的任意巢狀(遞迴除外),因此生成用例的約束很少,只需注意在定義函式時不要呼叫自身即可。

4.迭代設計感悟

從第一次作業到第三次作業,我基本上是按照迭代的思路進行設計。大致框架為:
第一次作業:只含有Data類及其繼承類,運用正則表示式解析字串,採取遞迴下降方法展開表示式。
第二次作業:擴充Data類,增加Sum類與Function類,引入運算介面及其實現類,自定義Tuple類作為項的結構。
第三次作業:完善三角函式的化簡,更改括號輸出方法。
可見,最大的跨越是在第一次到第二次作業。又由於第一次作業已經打好了基礎,整體框架脈絡比較清晰。
經過分析,我在第一單元的迭代設計有以下優缺點:

  • 優勢
    • 架構基本上依次順延,沒有進行較大範圍的重構。第一次作業已經採用遞迴下降法對字串進行處理,後續的作業雖然加入了更多複雜的概念,但整體處理方法能夠繼續使用,奠定了良好的基礎。
    • 加入新的類時,儘量統一它們與前期工作的關係。例如,Sum類和Function類仍然繼承Data類,它們的屬性和方法與其他資料類相似,只是在處理細節上有自己的特點,沒有必要另闢蹊徑。
    • 可以根據需求進行小範圍的更新而無需大量修改。例如,加入三角函式後,雖然資料的表示方式產生了很大的變動,但通過引入Tuple類直接解決了此問題,原有的類只需將屬性map更換為ArrayList即可。
  • 教訓
    • 第一次作業為圖方便採用了正則表示式,後續作業不得不拋棄此做法而另外設計文法分析。如果從一開始就採用此方法,會減少很多工作量。
    • 第一次作業沒有定義運算介面,後續作業由於複雜度陡然增加新設計了運算類。應該從第一次作業開始就採取此做法,這樣不僅可以降低程式碼的複雜度,還能使類的功能職責更加清晰,在debug時也能更快地定位問題點。
    • 前幾次作業沒有追求效能,不能將三角函式最簡化,後續才加入相關功能,導致工作量進一步加大。

5. 收穫與反思

第一單元的任務已經接近尾聲,回顧前三週的工作,自己有很多收穫,也有很多思考。

  • 首先,這三次作業我都成功完成了指導書列出的基本要求,實現了複雜表示式的展開,沒有出現毫無頭緒、望題發呆的情況,建立了信心。
  • 通過這些任務,我進一步加深了對面向物件設計的認識,實現了從面向過程到面向物件的思維轉變。
  • 對Java語言的一些特性有了更全面的瞭解。
  • 由於沒有仔細弄清指導書的要求,在最後一次作業中出現了低階錯誤。因為不掌握面向物件設計而出錯,尚能理解,但因為這種原因導致失分,不可原諒。對於一些人來說,不能完成一項任務往往不是因為能力不足,而是因為在沒有完全理解甲方的需求時就開工了。無論是現階段完成課內的作業,還是今後參加工作,知道自己要做什麼都是最重要的。