1. 程式人生 > 其它 >BUAA_OO_2021_第四單元總結:UML

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於我而言是“霧裡看花花非花,水中望月月非月”一般朦朧的存在,但通過不斷的鑽研與提煉,OO 慢慢地展現出了它的真實樣貌,也不再那麼令人可望而不可及了。

對測試的理解與實踐

寫到這裡,筆者不得不很慚愧地承認,這一學期的 OO 之旅最欠缺的就是測試模組。

第一單元,筆者只是手捏了一些具有複雜形式的表示式,如空格、前導零、連加連減、括號巢狀等。由於第一單元的bug比較容易復現,用一些簡單的資料就能復現出一些bug,而解決了這些簡單的問題,基本上覆雜表示式也就沒什麼坑點了。對於表示式的化簡,筆者也並未做出過多的探索。

第二單元,多執行緒排程實在不好手捏資料,於是就把指導書上的樣例刪刪改改,在不同時間投放給系統,簡單測試了一下排程和換乘,覺得沒有大問題就走人了。

第三單元是筆者鹹魚覺醒的時刻。筆者決定使用 Junit 更加全面、模組化地測試自己的程式,不遺漏任何一個方法。雖然還是有很多bug沒檢查出來,但我最起碼瞭解了 Junit 是怎麼用的,應該如何構造資料覆蓋率才高。

然後,通過聆聽 dalao 們的分享,我看到了測試一個程式的方法其實有很多,比如搭建評測機、根據不同的側重點自動生成資料、對拍等等。雖然這學期沒有嘗試這些方法,但以後一定會慢慢探索的!!!

我的收穫

首先最明顯的收穫就是程式碼能力顯著提升了!OO 課程教會了我面向物件的程式設計思想,教會了我如何設計程式的架構,讓我的程式碼從最開始的大規模重構發展到了只需要迭代、增加功能,讓我面對程式時也沒有了曾經那種無力感,這讓我對日後的專業學習有了積極的心理暗示,讓我相信一切都會越來越好的。

然後就是我通過這門課程學會了 java 語言,以及IDEA 真的太好用了!我感覺 java 現在成為了我最得心應手的語言,當然,學無止境,學習一門語言是快樂的,我很希望日後能掌握更多的語言,逐漸成為高階碼農。

還有一點點對功能測試的收穫,比如說 junit,比如說自動化測試,比如說對拍。

在此,還要特別感謝為課程付出了心血的老師們和豬腳哥哥姐姐們,以及幫助過我的每一個人!如果沒有你們的啟發,筆者將會在泥潭裡摸爬滾打很久很久,你們對於我具有不可替代的作用!

一些建議

從自己的體驗出發,筆者認為第四單元指導書中對 UML 解析器各個方法的描述可以更清晰一些,像第四單元第三次作業中的異常情況可以多給幾個示例,感覺現在的狀態有點難懂。

第一單元指導書的形式化表述有點讓人頭大,但好像也沒有更好的描述方式了。。。

最後,希望每次實驗過後能公佈答案,這樣課下能思考課上沒做出來的問題,收穫會更多!

寫到這裡,筆者本學期的OO之旅算是告一段落了,不管結果怎麼樣,求知的過程總是令人充盈的。那就祝OO完結撒花啦!我們有緣再會~