面向物件程式設計第四單元總結
面向物件第四單元總結
一、Unit 4分析總結
本單元作業基於UML的模型化設計,建立了一個支援三種UML圖的解析器,並具有有效性檢查功能。這單元的第一次作業是歷次最令我無從下手的一次,整個單元的核心在於讀懂UML圖所包含的內容,弄清楚UmlElements
之間的關係,才能在此基礎上佈置出良好穩定的架構。
1. 第一次作業分析
本次作業需要實現對UML類圖的解析,看似簡潔但需要大體構建出整個單元的框架(後幾次作業幾乎沒有大的重構,只是在其基礎上新增功能)。剛開始的時候有些棘手,如今看來主要思路有以下兩個方面:
-
解析的元素有什麼
需要我們從已有的UML模型中的元素入手,結合官方程式碼中的
UmlElement
-
解析器需要做什麼
這裡我們要從需求入手,仔細閱讀解析器支援的指令內容,弄懂我們需要記錄、整合、操作哪些元素,例如:查詢類關聯的對端是哪些類時,首先應記錄所有的
UMLClass
,其次需要整合類與類之間的聯絡,這就要求我們追蹤association
關聯關係。進一步,結合處理過的mdj
檔案,對應編寫程式碼的思路就會更加清晰。
2. 第二次作業分析
本次作業在第一次基礎上加入了UML協作圖和UML狀態圖的支援,並添加了六條指令。具體的學習和編寫程式碼的思路與第一次類似,還是跟隨教程學習規範UML圖,並閱讀官方包程式碼,分析具體指令內容三個方面。
值得一說的是,為了不將大部分程式碼堆疊在主解析器類中,我將程式碼結構做出瞭如下變化:
- 將自己建立的輔助
UmlElements
們放入了一個elements
包中; - 將原解析器類中的解析UML元素的程式碼放入了一個工具包
util
中的Parser
類,並將最終解析完畢的四個物件:UmlClass
類物件HashMap
,UmlInterface
介面物件HashMap
,UmlInteraction
順序圖物件HashMap
,UmlStateMachine
狀態機物件HashMap
作為全域性靜態變數供主解析器類訪問。
在做出如上改動後,主解析器類中只剩下與查詢指令相關的程式碼,各個類不會出現冗雜過長的結構,使得整體更加可讀。
3. 第三次作業分析
第三次作業添加了模型有效性檢查功能。針對每一個規則,分析其對哪些元素和哪些行為進行了規範,需要對架構有一定的修改。延續第二次作業的結構,我在util
包中新加入Checker
類,並通過靜態方法來完成查詢操作。完成檢查工作的同時也進一步加深了對UML圖的理解。
- 程式碼行數:
- 類圖:
4. 第四單元總結
本單元作業對於層次化、規格化、模型化均有一定的涉及,可以算是對本學期OO生涯的完結。在完成作業的過程中,既需要閱讀官方程式碼,也需要自己思考類之間的組織關係,運用到了許多之前出現過的圖演算法,幾乎所有程式碼都是由學生自行完成,對面向物件程式設計的能力有較大提升。
美中不足的是本次作業中出現了許多不明確的細節問題,希望課程組能對指導書進行進一步的優化,將目標內容解釋的更加清晰,多使用表格、圖形來描述,提高可讀性,而不是單一通過加粗和縮排。本單元的官方程式碼是最為複雜的一次,在閱讀上有一定的難度,但可以從中學會一些方法。
二、各單元架構設計與方法理解
1. 第一單元
第一單元目標是實現較為複雜的可巢狀表示式求導。有一說一,第一單元的遞進難度和重構規模相對於後幾單元甚至更高一些,好在程式碼編寫水平通過Pre的訓練有了一定的提升,因此在面對第一次作業時還比較順手。第一單元是互測最積極的單元,通過學習同屋同學的程式碼,觀摩別人的思路和架構,對於我自己的理解有了很多補充,也認識到了許多我沒有考慮周全的地方。
主要難點在於:
- 思考一個良好的類邏輯:表示式類、項、因子、加類等,好的架構會對程式碼邏輯和效能都有較大的提升。綜合下來,可以選擇樹形結構儲存,也可以按照表達式—項—因子的遞進關係來儲存。並在結構上可以進一步做出許多優化:刪去0項,合併簡單的同類項等,以及最後的化簡輸出。
- 遞迴下降:是用於解析表示式的較好的方法,在網上可以找到一些資料和模板供學習,但是其核心思想需要有一定程度的理解。
2. 第二單元
第二單元目標是實現多執行緒電梯執行系統。在寫作業之前,我練習了有關sychronized
與notifyAll
之間的相互操作,對於Java中的多執行緒邏輯有了一定的理解。在編寫程式碼時,主要考慮總等待佇列、排程器、電梯之間的三層次架構,為了防止死鎖的出現,我規定下層類不能訪問上層類的變數。由於LOOK演算法效能較好,每次作業的效能分還比較高,但第三次作業強行換乘的一些操作不是很符合邏輯,有待改進。
主要難點在於:
- 整理出良好的電梯邏輯結構:有的同學選擇多部電梯爭搶一個等待佇列,有的選擇加入排程器類進行分配;多種方法都可以滿足需求,重要的是避免死鎖和輪詢操作,實現正確可靠的電梯排程。
- 排程演算法優化:第一次作業使用LOOK演算法已經可以滿足效能要求;第二次作業
morning
的效能較低,我一直特別好奇大家都是對morning
選擇什麼策略;第三次作業的優化有點畫蛇添足的感覺,並沒有強制換乘的情況,因此使得我處在:向上優化太複雜,簡單優化沒屁用的尷尬局面。
第二單元的訓練和上機板塊中,還學習到了生產者——消費者模式、工廠模式、單例模式等多種Java中常見的設計模式,有著相當大的幫助。
3. 第三單元
第三單元是基於JML規格,實現多人網路社交系統。本次作業需要預先學習和熟練JML規格設計語言。整個編寫程式碼的過程大概是在:閱讀JML規格——整理需求——翻譯成Java語言——對效能做出優化。後兩單元的作業主要是在滿足在某種資料儲存架構下,對其訪問、查詢、修改等不同指令的操作,由於資料型別比較相似,因此幾乎都可以選用HashMap
儲存,在此基礎上進一步完善圖結構。
主要難點在於:
- 閱讀JML規格,並對整體程式碼需求有一定的把握,在此基礎上才能更好的實現需求。
- 提升效能的演算法改進:如堆優化的迪傑斯特拉、並查集等,學習了一些在Java中常用的圖演算法模板。
- 對細節的把控:許多指令雖然簡單,但就其邏輯上需要保證JML規格的嚴密,因此各種判斷條件一定要梳理清楚,否則會出現非常低階的錯誤。
4. 第四單元
前文已經提到,故略
三、各單元測試與實踐理解
1. 第一單元
第一單元編寫測試不算太複雜,可以通過Python的包來獲得標答和格式檢查。藉助室友大佬編寫的評測機,可以實現大規模、較高複雜度的資料生成、自動化測試、反饋的功能,同時也學習到了許多在Python中的知識,對遞迴下降有了更深刻的理解。
第一單元比較適合加斷點除錯,這個方法在de遞迴下降的bug時尤其有用,可以視覺化當前字串解析進度,跟蹤每個函式的進一步執行。因此,在除錯過程中大大增加了對IDEA的操作熟練度。
2. 第二單元
第二單元由於多執行緒特性,在本地測試難度較大,經常有同學出現本地跑十次一次沒錯,提交上去就裂開的情形。不僅如此,在輸出資料的合理性檢查也有一定的難度,實在是沒精力在用啥語言寫個測試程式。因此,第二單元作業主要選擇一些小規模、具有代表性的資料之間測試,這種方法可以幫助尋找電梯排程演算法的問題:例如轉向異常,開關門異常等等。對於同步問題,仍需要形式驗證來穩固了。
多執行緒除錯方法,有同學在研討課上分享了一些監控程式碼的外掛,對於程式碼程式效能、CPU佔用、死鎖等都有一定的監控能力,可以動態的看到程式碼底層的執行順序,對於理解多執行緒、編寫多執行緒有很大的幫助。最重要的是,我認為學習多執行緒,更應該關注的在於多執行緒架構的互動,理解底層程式碼順序,考察自己的程式碼在多執行緒下的表現——如何避免死鎖、如何提高CPU效率、視覺化對比不同架構帶來的不同表現……而不應該把深入學習的重心放在邏輯性上並不是那麼強的效能分上。希望課程組能夠進一步引導同學們對多執行緒更深入的學習和思考,從效能分的侷限中跳出來,相信更多同學會有能力有激情投入到其中。
3. 第三單元
第三單元測試資料體量較大、指令種類較多,我水平不支援我寫出美觀的評測機,因此只能以形式化驗證為主,覆蓋部分指令資料為輔的方式測試。本單元深刻體會到了覆蓋性測試的重要性,實在不能偷懶,否則就會像我一樣犯下age / people.size()
忘判斷空的情況,強測直接裂開,追悔莫及。
本次作業只通過編寫評測機測試了可能出現複雜度較高演算法TLE的情形:編寫程式生成萬條最複雜的指令並反饋CPU執行時間,保證滿足時間限制。
4. 第四單元
第四單元測試資料可以通過StarUML
手動建模——工具包匯出資料——執行評測的方式,雖然有些繁瑣,但還是屬於可以把握的範疇。我針對每個指令和有效性檢查的規則,模擬了一些可能出錯的邊界資料進行測試。有些遺憾的是許多規格在指導書中並沒有直接說清楚,因此需要不斷改進。
本單元對於良好的圖演算法有了進一步的理解,算是補上了第三單元偷的懶。尋找環、尋找聯通路徑等,對Java中其他資料結構如:Stack
、LinkedList
、Queue
等也有了較為熟練的運用。
四、課程收穫
OO課程轉眼間過去,一看資料夾已經有長長一面的歷次Homework
,現在再回想起來一時感慨萬千。在寫本次部落格總結時,我翻看了從寒假的Pre一直到最後一次作業的程式碼,明顯感覺到自己的程式碼風格、格式、類的組織、美觀性等都有了顯著的提升:從Pre冗雜、拼湊、高度耦合的程式碼,到如今邏輯更加清晰,類與類各司其職,不得不說經過一學期的面向物件程式設計訓練,我有了很大的收穫。
- 通過每單元作業前序知識的準備,我學習到了許多面向物件的核心內容:層次化設計、多執行緒設計、規格化設計與JML語言、模型化設計與UML圖。應該深刻領悟其中蘊含的思想並融合到自己編寫程式碼的習慣中去。
- 通過每單元的上機訓練,我學習到了與每單元核心內容相輔相成的知識:Java的多種設計模式、JML語言的編寫、UML類圖的理解等,都對作業內容進行了一定的擴充套件和加深。
- 通過每單元同學們的研討分享,我可以集大家之所長,相互交流提升,查漏補缺。
- 通過每單元最重要的作業,我以實踐的方式真正接觸面向物件思想,感悟程式碼的執行,其中的許多:方法實現方式的權衡、類架構的取捨、修改與重構等,都為以後在面對實際問題時打下了穩固的基礎。
官方的話就說這麼多,面向物件程式設計的魅力遠遠不止這些,OO課只是我們不斷學習路上的開始。在今後學習生活中,我們仍需要保持熱情,充分利用學習到的方法,進一步印證與思考,才能最大程度的提高自身的能力。
五、改進建議
- 希望課程組能夠設立不同於效能分的措施來調動同學們進一步探索的熱情。效能分只能作為學習水平高低的一個小方面的體現,但教學初衷應該是引導同學們的思維。在多執行緒、JML、UML單元,可以設立一些其他的目標或可探索的內容來引導大家在滿足測試要求下的強化學習。
- 課程組可以適當為同學們提出一些編寫評測機的方法和思路,或者開設類似的討論區引導同學們自己學習:可以運用其他語言、可以學習某些高效的方法。對於我來說,適當的引導會讓我對測試方面有更為濃厚的興趣。
- 希望進一步增強課程網頁討論區的優化:第三四單元細節較多時,討論區蓋樓太過嚴重,可讀性有待提高。
- 希望指導書的規範性、美觀性都能做出一定的提升:尤其是針對部分描述不清的歧義、在
markdown
中使用表格來規範一些類似於指令、規格的操作其實更加可讀,而不是單一的使用縮排和加粗。