第一次OO博客作業 前言 面向對象課程已經經過了4周的時間。前三次作業全部是關於多項式求導的相關內容,內容由易到難,同時我也開始逐漸深入感受學習面向對象的各項特征,逐漸將自己的編程風格從C向真正的面向對象語言轉換。同時我還接觸了DEBUG和互測屋這樣嶄新的學習方式,在閱讀別人代碼的過程中不斷增強自己 ...
第一次OO博客作業
前言
面向對象課程已經經過了4周的時間。前三次作業全部是關於多項式求導的相關內容,內容由易到難,同時我也開始逐漸深入感受學習面向對象的各項特征,逐漸將自己的編程風格從C向真正的面向對象語言轉換。同時我還接觸了DEBUG和互測屋這樣嶄新的學習方式,在閱讀別人代碼的過程中不斷增強自己的編程能力和學習能力。
本篇博客將結合3次作業內容,分別從題目的理解思路,代碼風格和度量,BUG的產生以及修複和Applying Creational Pattern共4個方面分析我這四周以來的工作。
一、第一次多項式求導作業
第一次作業相對之後的2次簡單許多,但是由於是第一次運用JAVA編寫這樣有一定規模的程式,對我還是有一定挑戰的。
我將第一次作業大致分為3個階段,包括多項式的格式檢查,多項式的求導以及最後的化簡輸出。在第一步的格式檢查中先檢查空格部分,再將空格刪除,用一長條正則匹配所有字元。在求導部分對每一項進行匹配,共有5種格式可能,分別對這5種情況進行求導,同時將結果存入HASHMAP中,最終在最後的化簡輸出函數中對指數相同部分,以及0,1進行化簡,最終輸出。
以下為第一次作業的類圖:
相信這應該是我所寫過的最面向過程的JAVA程式,整個程式自始至終只有一個類,並且整個程式的結構類似於C程式那樣流水線的順序結構,將所有函數以及數據都封裝在同一個類里。這直接導致了在第二次作業的無法擴展,只能推倒重來。
第一次作業BUG分析
在第一次作業我的程式在測試中總共檢出過2個BUG,分別為正則爆棧以及邏輯判斷式中的計算順序問題。
首先是正則爆棧問題。在第一次作業中由於第一次使用正則表達式,沒有採取分段匹配的方法,而是對整段統一一起匹配,如下圖所示。
由於在第一次寫正則表達式時使用貪婪匹配,直接導致程式爆棧。在DEBUG中將其改為獨占模式進行匹配,得以解決問題,但在風格上無疑是很不好的。因此在後2次作業中進行了逐項匹配。
第二個BUG屬於比較低級的錯誤
問題出現在mlj2中,在BUG修複前沒有括弧,而判斷目的是先進行或運算再進行與運算,與預設運算順序不同,導致格式判斷出現錯誤。
總結
總體第一次作業難度不高,但由於是第一次編寫有一定規模的JAVA程式,在程式風格,重構考慮以及細節等很多地方都沒有做到位,也算是給自己長了一次教訓。
二、第二次多項式求導作業
第二次作業相對於第一次作業增加了sin(x)和cos(x)求導,相對於第一次作業需要增加對於sin(x)和cos(x)的正則識別,同時在求導規則和化簡上增加了一定的難度。總體上格式判斷與第一次求導作業相同,但了可能的三個運算符與數字的組合,需要在第一次求導格式判斷的基礎上增加一個新的判斷函數。在最終結果方面,將每一項變為a*x^b*sin(x)^c*cos(x)^d的形式,併在最後根據情況進行化簡。
以下為第二次作業的類圖:
在第二次作業中我首先將整個多項式作為一個Poly類,對其進行空格檢查。在刪除空格後通過加減號進行劃分,將整個多項式分解為各個獨立的項,在對每項進行格式檢查後進行求導,將求導形成的 abcd4元組變換成字元串存入Arraylist中。最後將繫數項相同的部分以及1和0進行化簡,最後輸出結果。復用了第一次作業的空格判斷函數,但在函數求導上與第一有較大差別。第一次作業使用HASHMAP進行儲存,而這一次使用ARRAYLIST,於是只能大規模重寫。
總體代碼風格上較第一次有比較大的改善。我總共建立了2個類:多項式類和項類,在多項式類中進行空格和符號的格式檢查,以及最後的化簡輸出工作。在項類中進行每一項的格式檢查以及求導工作。但在細節等很多方面都有可以增加的地方,例如使用介面進行規範。同時我也沒有讓項類繼承多項式類的部分特性,而是重覆編寫了許多相同功能的函數。以及在格式檢查傳遞錯誤信息中我使用了變數傳遞,雖然在原理上可行,但是是不被推崇的編程方法,因此在第三次作業中通過拋出錯誤的方法替代了該部分的方法。
第二次求導作業中的BUG:
第二次作業在結構上並沒有BUG出現,但在細節上出現了BUG。在對1進行化簡時沒有考慮項內只有1的情況,導致將為1的項整個消去了,產生錯誤。這也提醒我在編寫這樣有一定代碼量的程式時不但要註重總體的思路和結構,還要小心這樣的細節之處。同時在DEBUG時要充分考慮各種情況。正是由於這樣的一個小錯誤使我直接掉入C檔,算是吃一塹長一智吧。
三、第三次多項式求導作業
第三次作業相對第二次作業增加了多項式的嵌套情況,在求導上複雜度增加,無法只通過4元組的形式表示所有的求導結果。同時在格式判斷,項切割等各個方面增加了難度,需要考慮括弧等各種新的因素。程式類圖如下所示:
我的程式將可能出項的結構情況大致歸為3類,包括多項式類(Poly)、項類(MPoly)和因數類(Subpoly)。在多項式類中我大致進行了3項工作,包括多項式的空格以及符號檢查,對多項式中項的劃分以及將項的求導結果進行整合,形成多項式的求導結果。在項類中我大致進行2項工作,對項進行分割形成因數,同時將因數求導結果進行整合,形成項的求導結果。在因數類中進行2項工作,包括對因數格式的檢查以及對因數的求導。在這3類之外為了方便區分系統EXCEPTION以及格式錯誤2種情況引起的WRONG FORMAT!,我定義了一個自定義異常DException.
由於第二次作業考慮對於擴展的需求,在這一次作業中我成功復用了第二次作業所有格式判斷函數以及部分求導函數。但這一次作業在細節上仍然有很多不足之處。我的思想仍然沒有徹底擺脫C的限制,在第二次作業中同樣沒有使用類的繼承以及介面等JAVA特性的功能。同時可以從類圖中看到,我不必要的屬性以及類內部分方法的複雜度仍然過高,這都是我在接下來亟需轉變的問題。如果仍然將自己的思想局限於面向過程中我勢必會遇到瓶頸和障礙。
第三次作業BUG:
在第三次作業中由於個人能力和時間有限並沒有對整個多項式進行化簡工作,因此相比前2次作業在化簡時的BUG,我這一成功通過了所有強測案例。同時為了避免不必要BUG的出現,我在另一方面增加了最終表達式的複雜性,方法是將所有的+轉變為+1*,負號轉化為-1*,但卻忘記考慮了一種特殊情況,即將 sin(-23)轉變為sin(-1*23),導致了互測時BUG的出現。這也提示我在編程時要從實際出發,如果一直使用這樣的小聰明必定會導致意外出現。
第三次作業總結
在第三次作業中我成功實現了對前2次作業的擴展,通過遞歸以及進一步的劃分類的方法實現了嵌套求導。但在類繼承、介面實現這些JAVA特性結構的使用上仍然有很大的不足之處,同時並沒有實現最終的化簡工作。
四、關於互測屋和DEBUG
我對別人的DEBUG方法相對而言分為2步。第一步即在自己編寫程式的過程中將可能出現的BUG記下來,然後在互測時攻擊別人,其中主要包括格式錯誤以及可能出現的爆棧錯誤。例如空串,1,1-1,0*x^0等這樣的常見錯誤。通常這種方法特別有效,將近70%的錯誤都可以通過這樣的方法解決。第二步就是閱讀他人的代碼。由於要閱讀將近7個人的代碼,沒有時間一行一行讀,我採取的做法是挑選重點讀,通常是匹配的正則表達式,求導過程以及最終的化簡步驟等幾個場景愛你犯錯誤的地方。通過這2步的配合90%的錯誤都能被找到。
在3個星期的互測中,通過閱讀他人的代碼我也開拓了眼界,學到了不少東西。包括工廠函數,以及優秀正則表達式書寫等各項新的知識。同時也促使我充分反省自己糟糕的代碼風格。
五、Applying Creational Pattern
由於使用JAVA仍然不夠熟練,在3次作業中我都沒有充分考慮到重構的問題。三次作業的求導過程都截然不同,全部重寫。但格式判斷函數,即對空格以及加減號合法性判斷得到了復用。
六、總結
經過了3個星期的多項式編程,我初步掌握了JAVA的編程方法和麵向對象的基本思想,目前仍有2項不足之處,首先我的思想仍然很大程度上收到C的限制,總是想通過面向過程的方法解決問題。第二是對JAVA語言的部分特性不太熟悉,當別人介面,繼承,工廠函數非常熟練時,我仍然在把JAVA當C寫,使用多個函數定義想解決一切問題,這顯然是不合適的。在接下來的學習和編程中我需要充分認識到自己的不足,從他人的代碼,網上以及課堂上充分學習,使自己成為一個合格的JAVA程式員。