【面向對象】第四單元UML總結及面向對象課程學期總結

1、第四單元的架構設計

第一次UML做業

第一次做業比較簡單,僅包含類圖的解析。正確理解UML元素的含義,以及每種UMLElement的各個屬性的所指向的東西,就能比較容易地完成這次做業。算法

這裏我構建了兩個類:ClassRelations以及InterfaceRelations用來存儲類和接口所包含的屬性、方法等類圖的基本信息,同時還要保存父類(父接口)、實現的接口,用來遞歸查找。是一種比較容易想到的實現方式。編程

類圖以下:設計模式

爲了加快對ClassName的查找和判斷,使用了一個鄰接表來存儲同名的類,方便查找相應的類。安全

private HashMap<String, ArrayList<UmlClass>> classNameMap = new HashMap<>();

    private void checkClassName(String className)
        throws ClassNotFoundException, ClassDuplicatedException {
        if (!classNameMap.containsKey(className)) {
            throw new ClassNotFoundException(className);
        } else if (classNameMap.get(className).size() > 1) {
            throw new ClassDuplicatedException(className);
        }
    }

第二次UML做業

第二次做業在第一次做業的基礎上,增長了對UML狀態圖和UML時序圖的解析。此外,還增長了三個模型有效性檢查的規則,分別是:不含重名的成員、不能循環繼承、不能重複實現接口。bash

與第一次做業相比,總體的架構變化不大,總的思想仍然是把每一種UML元素放到對應的UML圖中,根據需求對這些數據加以維護。總體稍加改動後直接繼承上次的做業。多線程

本次實現的MyUmlGeneralInteraction直接繼承了上次的MyUmlInteraction。對於狀態圖和時序圖,與上次做業相似的,我建立了兩個類StateMachineRelationsSequenceRelations用來保存與狀態圖和時序圖相關的信息。架構

類圖以下:併發

對於模型有效性的檢驗編程語言

  • R001:針對下面給定的模型元素容器,不能含有重名的成員(UML002)

    與檢測類名重複相似的,在ClassRelations類中,添加屬性和關聯對端的時候,對同名的屬性和關聯對端進行計數,就能夠得到找到重名的成員。

  • R002:不能有循環繼承(UML008)

  • R003:任何一個類或接口不能重複繼承另一個接口(UML009)

    這兩個規則都是和繼承或接口的實現相關的,因此放在一塊兒處理。繼承/實現關係構成了一個有向圖,循環繼承和屢次實現接口的優先圖,具備以下特色:

    • 循環繼承的充要條件是:有向圖中存在環(節點到節點自身存在一條路徑)
    • 重複繼承的充要條件是:有向圖中,一個節點到另外一個節點存在不止一條路徑

    因此,將邊權定義爲優先圖節點之間的路徑數目,那麼也就能同時判斷是否存在循環繼承和重複繼承

    對於節點i到節點j的路徑數目,對於中間節點k,存在以下的關係:route(i, j) = route(i, j) + route(i, k) * route(k, j)

    (貌似是動態規劃的狀態轉移?有沒有算法大佬能夠講一下,沒學過不是很懂。順便期待下學期算法有一個好的收穫)

    使用UmlClassOrInterface接口對類和接口的關係統一建模,具體的代碼以下:

    private HashMap<UmlClassOrInterface, HashMap<UmlClassOrInterface, Integer>>
                extensionGraph = new HashMap<>(); //包含繼承關係和接口實現關係
    
      public static <T> void floyd(HashMap<T, HashMap<T, Integer>> graph) {
            for (T k : graph.keySet()) {
                for (T i : graph.keySet()) {
                    if (i.equals(k) || !graph.get(i).containsKey(k)) {
                        continue;
                    }
                    int ik = graph.get(i).get(k);
                    for (T j : graph.keySet()) {
                        if (k.equals(j) || !graph.get(k).containsKey(j)) {
                            continue;
                        }
                        int kj = graph.get(k).get(j);
                        if (!graph.get(i).containsKey(j)) { // 更新路徑數
                            graph.get(i).put(j, ik * kj);
                        } else {
                            int newCnt = graph.get(i).get(j) + ik * kj;
                            graph.get(i).put(j, newCnt);
                        }
                    }
                }
            }
        }
    
      protected Set<UmlClassOrInterface> check008() {
            Set<UmlClassOrInterface> set = new HashSet<>();
            for (UmlClassOrInterface i : extensionGraph.keySet()) {
                if (extensionGraph.get(i).containsKey(i)) {
                    set.add(i);
                }
            }
            return set;
        }
    
        protected Set<UmlClassOrInterface> check009() {
            Set<UmlClassOrInterface> set = new HashSet<>();
            for (UmlClassOrInterface i : extensionGraph.keySet()) {
                for (UmlClassOrInterface j : extensionGraph.get(i).keySet()) {
                    if (extensionGraph.get(i).get(j) > 1) {
                        set.add(i);
                    }
                }
            }
            return set;
        }

2、四個單元中架構設計及OO方法理解的演進

架構設計是面向對象這門課的重中之重。因爲咱們的課程是按照單元推薦,每一個單元的每一次做業都是在前一次的基礎上,進行增量任務,因此一個好的架構可讓後續的做業更加容易完成。

  • 第一單元:多項式求導

    前兩次的做業由於需求還比較簡單,還算是有一個比較看得過去的架構。把多項式分解爲單項式,再把單項式分解成冪函數和三角函數,一個多項式的求導問題就被分而治之。就是下降耦合,抽象出各個不一樣的類,將它們獨立出來,再把每一個對象組合在一塊兒來統一處理。

    可是隨着第三次做業的發佈,這個架構設計的弊端就顯現出來了。擴展性較差,致使第三次做業加上嵌套求導以後,幾乎推倒重寫。仍是說明前兩次做業對面向對象機制的理解不夠深入,以及對Java語言掌握不夠熟練(不會使用接口泛型等特性)

  • 第二單元:多線程電梯

    多線程電梯調度主要就是要理解清楚生產者-消費者模型以及發佈-訂閱模型這些課上講到的重要的多線程編程的設計模型。多線程最重要的問題就是線程的同步與互斥、線程間通訊的問題。

    第二單元多線程電梯調度主要運用的就是「生產者-消費者模型」,構建一個兩級的關係,經過共享隊列在線程間傳遞信息。輸入線程與調度器線程經過共享隊列交互,調度器線程再與電梯線程經過共享隊列交互。這個架構設計延續了三次做業,主要的變化都是調度器內部和電梯內部的調度算法。

    這個單元,課上老師也介紹了一些設計模式,好比單例模式、工廠模式等等。雖然實際寫代碼的時候沒有特別注意使用這些設計模式,可是這些學習設計模式的思想,也是在知道咱們怎麼去設計類,怎麼去設計接口,使得程序具備良好的擴展性和魯棒性。固然,最重要的仍是理解了多線程編程的方式和要點。

  • 第三單元:JML規格設計

    Java Modeling Language 是用於Java語言建模的語言,是一種契約化的設計思想。這個單元主要是圍繞着圖論展開的,因爲有JML規格做爲提示,總體比較順暢。做業難度依次遞增,從路徑到地鐵圖層層遞進。將不一樣的需求(最短路徑,最少票價,最少換乘)分別用不一樣類的建模完成,下降耦合。因爲都是圖,因此把通用的圖的算法單獨提出來放到一個類,做爲靜態方法來調用(其實這樣是有點危險的,一旦這裏出錯,全部地方都出錯了,嗚嗚嗚我就錯在這了)

    JML爲程序的開發設計提供了一個統一的規範規格,雖然估計JML實際應用不是不少,JML描述的規格,對方法、類等程序單元進行了嚴格的約束,這些正確詳實的規格,相較於天然語言,能更加規範地描述需求,減小歧義,保證開發的速度與質量。這種」先設計規格再實現「的約定對於大型工程的協同開發有不少的好處。

  • 第四單元:UML圖解析器

    這一單元主要的任務是解析UML圖中的各類元素。理清楚UML各個元素的各個字段的意義以及之間的關係之後,推動的就比較順利。

    根據UML圖的組織形式,能夠很容易地聯想到仿照UML圖地組織形式來構建每一個類,按照類圖、順序圖、狀態圖分別構建模型和存儲相應數據。把實現的各部分劃分紅不一樣的責任單元,創建各個類來分別負責完成各自的任務。與第三單元有些相似。

3、四個單元中測試理解與實踐的演進

  • 第一單元:多項式求導

    學習了討論區編寫測試腳本的方法,我採用以下的方式來發現別人的Bug:

    1. 把全部人的代碼編譯打包爲.jar文件
    2. 編寫測試數據(人工或自動生成),保存在testData.txt文件中
    3. 編寫bash腳本,在Windows平臺使用Git bash執行
    4. 編寫Python腳本sympy用來計算標準答案,以及互測屋全部輸出的答案
    5. 將第三步和第四步的數據輸出保存到log.txt文件中,人工比對

    使用到的工具包括:Python Sympy, Git bash, VS code等。

    第一單元因爲沒有官方包的介入,輸入輸出都是本身處理,因此WRONG FORMAT是測試的重中之重。

  • 第二單元:多線程電梯

    多線程編程比較特殊,因爲多線程並行具備不肯定性,且不一樣的調度算法會形成不一樣的輸出結果,因此不存在惟一的正確答案,評測機實現起來也有點複雜。因此我自測階段,沒有進行大量數據的測試。

    互測階段,主要是讀代碼,看有沒有出現一下幾種問題:

    • 線程安全問題(共享資源有沒有上鎖)
    • 輪詢,容易形成CPU超時
    • 調度算法,容易形成運行總時間超時
  • 第三單元:JML規格設計

    第三單元使用了很重要的一個測試工具:JUnit。

    單元測試是一個強有力的測試工具。相比大量數據的黑盒測試,JUnit單元測試能夠在更快速的找到代碼漏洞,花費更少的時間,達到很好的驗證正確性的效果。JUnit還有一個有點是有測試覆蓋率的指標,這是隨機數據的測試所不能比擬的。

    除了使用JUnit進行測試,還構造了一個比較強的隨機數據生成器來進行測試,與同窗的輸出進行比較。(仍是晚了,發現Bug的時候已經截至了)

  • 第四單元:UML圖解析器

    第四單元用StarUML花了幾個比較特殊的圖,好比重複繼承、循環繼承相關,以及帶多的環的狀態圖等特殊狀況,來測試代碼的正確性,並重點測試了幾個用到了深度優先搜索算法的指令。期末考試也比較忙,測試頻次不是不少。

測試先行是我印象最深的。

不管是什麼工程,寫代碼、連電路、焊板子這些,最重要的都是進行全面的測試。測試必定要和編寫代碼同步進行,或者先於寫代碼完成。第三單元最後一次做業慘痛的教訓讓我記住了「測試先行」這個道理,不要等到最後再匆匆忙忙測試而後提交,一個隱蔽的錯誤形成的可能就是滿盤皆輸。

4、總結本身的課程收穫

  • 優秀的IDE是事半功倍的前提:IDEA真的很好用
  • 能較爲熟練地使用Git、GitLab、UML等現代工具
  • 比較熟練的掌握了一門面向對象的編程語言:Java,以及良好的代碼風格
  • 瞭解並掌握了多線程併發編程的編程方式和技巧
  • 收穫了面向對象的程序設計思想、原則
  • 基本的軟件測試意識、能力、方法技巧,以及如何作一個狼人
  • 軟件架構設計意識和一些經常使用的設計模式,好比工廠模式、單例模式等
  • 抗壓能力和加班能力沒有周末,是爲之後996作準備
  • 迭代開發的能力,以及做爲一個成熟地乙方應該要安心接受甲方(助教組和老師)的需求變更

一個學期的OO課程終於結束啦。就像登山同樣,如今到了山頂終於能夠喘口氣了。每週的做業走在催逼着本身不斷前進,雖然一個學期基本沒過過一個舒服完整的週末,但回過頭來看,這一萬多行代碼,每一個單元博客的總結記錄,看獲得這一路上的進步和收穫。雖然有作的不盡人意的地方,但仍是蠻有成就感的。

至少最後表彰總結課上沒有空手回去😁

5、對面向對象課程的建議

  1. 開個測試分享區,能夠分享測試機或者測試數據

  2. 第二個是但願互測能有些改變,這個我在第一單元的博客中也寫到過。

    這三次的互測後,我相對如今的互測制度提一點小小的建議:

    1. 仍然劃分A, B, C三檔,可是分組把這三組混合編組,例如8人間能夠{2A, 3B, 3C},7人間{2A, 3B, 2C}
    2. 找到某個等級做業的Bug得對應等級得分,而與本身的做業等級無關
    3. 這樣作得好處是:每一個人均可以看到不一樣水平的代碼,給C組和B組的同窗更多學習的機會;避免了高段位「大眼瞪小眼」的尷尬,還有低段位「菜雞互啄」的無趣;找到高段位的Bug更有成就感和分數獎勵
    4. 缺點是:規則較爲複雜,實現起來可能比較麻煩,並且不必定每一個人都接受這種制度

    有同窗說:「通過這三次互測,個人bash腳本和Python 寫的比原來好多了。」

    固然,這些都只是我我的的想法,拋磚引玉,還請助教組學長學姐和老師們能研究出更好的制度,迴歸互測的本質。

    或者簡單一些,把互測的人數減小到5至6人可能會合適些,這樣能夠多讀代碼,以避免一些同窗互測階段直接放棄。

  3. 研討課參與程度不過高,感受「研討」的氛圍不是很明顯。

  4. 感受第三單元能夠提到第一單元來。特別是多項式求導做爲第一單元,並且最後一次做業,確實有點困難,不如先從JML開始,逐步熟悉Java語言和麪向對象的建模方式。

相關文章
相關標籤/搜索