BUAA_OO_2021_第四單元總結:UML
架構設計
筆者認為本次作業很重要的一部分就是UML類圖中各個元素的整理與分類。
筆者將傳入的umlElements中的所有元素進行分類,在建構函式中對各個類圖進行了初始化。以第三次作業為例,筆者將所有型別的元素分為了四批來處理,第一批處理UmlClass,UmlInterface,UmlInteraction,UmlStateMachine;第二批處理UmlAttribute,UmlOperation,UmlAssociation,UmlGeneralization,UmlInterfaceRealization,UmlMessage,UmlLifeline,UmlRegion;第三批處理UmlParameter,UmlState,UmlPseudostate,UmlFinalState,UmlTransition;第四批處理UmlEvent。之所以要分批處理,是因為umlElements中的元素並不保證順序,有可能類的屬性比類先傳進來,為了避免空指標現象,我們需要將更巨集觀的元素優先處理。當然,這並不是效能最好的方法,如果直接對umlElements中的元素進行順序處理,先把找不到歸屬的元素都存起來,留到第一輪之後再處理,迴圈次數將會減少,效能會變好。
Uml類圖
對OO方法理解的演進
第一單元
如今回首第一單元,它仍然是一場噩夢。筆者認為第一單元是OO難度的巔峰,尤其是當時對架構一片空白,腦子裡還沒建立起面向物件的概念,而且自身程式設計能力也很拉跨的時候,面臨一個需要用遞迴下降逐層拆解巢狀關係並求導的大工程時,我的生活簡直一團亂麻。
筆者的架構大概是先建立了一個Factor抽象類,然後讓Constant,Sin,Cos,Power,Monomial,Polynomial都繼承Factor類,在每個類中覆寫自己的getIndex()
和derivation()
方法,然後按照求導法則求導。由於多項式和單項式是互相巢狀的,拆解過程還是比較繁瑣的,很容易產生bug。
Uml類圖
多執行緒電梯排程可以說是OO課程最有特色的一單元。筆者感覺對於本單元,只要開頭架構做得好,後面的困難就少。筆者採用的是分散式排程策略,每部電梯都有它自己的等待佇列,由總排程器按照一定規則為每部電梯分配乘客。本單元第二次、第三次作業增加的程式碼量不大,只需適當改變排程策略和換乘策略即可。
在電梯排程的debug過程中,我們也學會了很多執行緒安全問題,如死鎖、執行緒飢餓等,這些對於未來的程式設計都意義深遠。
Uml類圖
第三單元
JML是難度最小最容易上手的一單元,但也是坑很多的一單元。關鍵是要根據JML提煉出每個方法的功能是什麼,不能對著JML無腦寫。這一單元的主題是社交網路,涉及到了一些圖論演算法,如dijkstra演算法求最短路徑(用PriorityQueue可以實現該演算法的堆優化)、並查集求解連通塊個數等。
堆優化dijkstra演算法
public int dijkstra(Person fromPerson, Person toPerson) { Map<Person, Boolean> tag = new HashMap<>(5000); //是否被訪問過,Key是Person Map<Person, Integer> dist = new HashMap<>(5000); //從源點start到各個頂點的最短距離,Key是Person Queue<Vertex> pq = new PriorityQueue<>(5000, new Comparator<Vertex>() { @Override public int compare(Vertex o1, Vertex o2) { return o1.getDistance() - o2.getDistance(); } });//優先順序佇列,最小堆,邊權值越小優先順序越高 for (Person person : people.values()) { tag.put(person, false); dist.put(person, INFINITY); } pq.add(new Vertex(fromPerson, 0)); dist.put(fromPerson, 0); while (!pq.isEmpty()) { Vertex v = pq.poll(); MyPerson topPerson = (MyPerson) v.getPerson(); if (tag.get(topPerson)) { continue; } tag.put(topPerson, true); for (Map.Entry<Person, Integer> entry : topPerson.getLinks().entrySet()) { int min = dist.get(entry.getKey()); int temp = dist.get(topPerson) + entry.getValue(); if (min > temp) { dist.put(entry.getKey(), temp); pq.add(new Vertex(entry.getKey(), temp)); } } } return dist.get(toPerson); }
第四單元
第四單元實現了一個 UML 類圖解析器,重點在於建立自己的 MyXXX 類來封裝相關的元素,組成模型。有了第三單元 JML 的鋪墊,第四單元的 UML 不難上手,但UML第三次作業判斷異常的時候情況比較複雜,需要認真體會重複繼承、迴圈繼承到底指的是什麼,怎樣不重不漏地實現這些功能。
對測試的理解與實踐
寫到這裡,筆者不得不很慚愧地承認,這一學期的 OO 之旅最欠缺的就是測試模組。
第一單元,筆者只是手捏了一些具有複雜形式的表示式,如空格、前導零、連加連減、括號巢狀等。由於第一單元的bug比較容易復現,用一些簡單的資料就能復現出一些bug,而解決了這些簡單的問題,基本上覆雜表示式也就沒什麼坑點了。對於表示式的化簡,筆者也並未做出過多的探索。
第二單元,多執行緒排程實在不好手捏資料,於是就把指導書上的樣例刪刪改改,在不同時間投放給系統,簡單測試了一下排程和換乘,覺得沒有大問題就走人了。
第三單元是筆者鹹魚覺醒的時刻。筆者決定使用 Junit 更加全面、模組化地測試自己的程式,不遺漏任何一個方法。雖然還是有很多bug沒檢查出來,但我最起碼瞭解了 Junit 是怎麼用的,應該如何構造資料覆蓋率才高。
然後,通過聆聽 dalao 們的分享,我看到了測試一個程式的方法其實有很多,比如搭建評測機、根據不同的側重點自動生成資料、對拍等等。雖然這學期沒有嘗試這些方法,但以後一定會慢慢探索的!!!
我的收穫
首先最明顯的收穫就是程式碼能力顯著提升了!OO 課程教會了我面向物件的程式設計思想,教會了我如何設計程式的架構,讓我的程式碼從最開始的大規模重構發展到了只需要迭代、增加功能,讓我面對程式時也沒有了曾經那種無力感,這讓我對日後的專業學習有了積極的心理暗示,讓我相信一切都會越來越好的。
然後就是我通過這門課程學會了 java 語言,以及IDEA 真的太好用了!我感覺 java 現在成為了我最得心應手的語言,當然,學無止境,學習一門語言是快樂的,我很希望日後能掌握更多的語言,逐漸成為高階碼農。
還有一點點對功能測試的收穫,比如說 junit,比如說自動化測試,比如說對拍。
在此,還要特別感謝為課程付出了心血的老師們和豬腳哥哥姐姐們,以及幫助過我的每一個人!如果沒有你們的啟發,筆者將會在泥潭裡摸爬滾打很久很久,你們對於我具有不可替代的作用!
一些建議
從自己的體驗出發,筆者認為第四單元指導書中對 UML 解析器各個方法的描述可以更清晰一些,像第四單元第三次作業中的異常情況可以多給幾個示例,感覺現在的狀態有點難懂。
第一單元指導書的形式化表述有點讓人頭大,但好像也沒有更好的描述方式了。。。
最後,希望每次實驗過後能公佈答案,這樣課下能思考課上沒做出來的問題,收穫會更多!
寫到這裡,筆者本學期的OO之旅算是告一段落了,不管結果怎麼樣,求知的過程總是令人充盈的。那就祝OO完結撒花啦!我們有緣再會~