1. 程式人生 > 其它 >OO第四單元總結 —— UML系列

OO第四單元總結 —— UML系列

OO第四單元總結 —— UML系列


一、本單元作業架構設計


  1. UML類圖(主幹部分)

    類圖中只展示了主幹部分,除此之外還有針對每一種UmlElement的包裝類,如:

    package analyzer;
    
    import com.oocourse.uml3.models.common.NameableType;
    import com.oocourse.uml3.models.common.Visibility;
    import com.oocourse.uml3.models.elements.UmlAttribute;
    import com.oocourse.uml3.models.elements.UmlElement;
    
    public class MyAttribute {
    
        private final UmlAttribute umlAttribute;
        
        public MyAttribute(UmlElement element) { umlAttribute = (UmlAttribute) element; }
        
        public Visibility getVisibility() { return umlAttribute.getVisibility(); }
        
        public NameableType getType() { return umlAttribute.getType(); }
        
        public String getParentId() { return umlAttribute.getParentId(); }
        
        public String getName() { return umlAttribute.getName(); }
        
        public String getId() { return umlAttribute.getId(); }
    
    }
    
  2. 類的設計

    • 包裝類

      UmlElement的包裝類中,儲存了官方包提供的UmlElement物件中沒有儲存的重要資訊(如類的繼承關係,各種屬性等),也實現了對官方包物件的部分重要資訊的查詢方法,以此來更加便捷地管理資料。

    • Database

      主要負責接受傳入的UmlElement... elements,並對有用資訊進行提取與儲存。

      處於對類的行數限制的要求,以及明確類的分工的考慮,在第二次作業時將其獨立分出作為一個單獨的類。

      在第三次作業中的R005R006在這一初始化步驟即可被發現,因而該類也負責對這兩個錯誤的識別。

    • CheckForUml

      在第三次作業時加入,主要負責接受初始化後的Database

      ,檢查相應的8條規則。

  3. Database的初始化

    基本思路是遍歷傳入的UmlElement... elements,根據其型別進行包裝,之後裝入相應的容器並與相應的元素建立聯絡。

    考慮到不同型別元素在遍歷時先後次序的不確定性,選擇進行多輪遍歷,並按照元素之間的依賴關係在每一輪遍歷時只處理部分型別的元素,以此來避免記錄元素之間的關聯時出現空指標異常。

    具體分類如下:

    • 第一輪:

      UML_CLASS
      UML_INTERFACE
      UML_ASSOCIATION
      UML_STATE_MACHINE
      UML_REGION
      UML_TRANSITION
      UML_COLLABORATION
      UML_INTERACTION
      
    • 第二輪:

      UML_ATTRIBUTE
      UML_OPERATION
      UML_ASSOCIATION_END
      UML_GENERALIZATION
      UML_STATE
      UML_PSEUDOSTATE
      UML_FINAL_STATE
      UML_EVENT
      UML_OPAQUE_BEHAVIOR
      UML_LIFELINE
      
    • 第三輪:

      本輪不進行遍歷,而是在已經處理的元素之間建立聯絡,包括:

      classinterface之間新增association

      stateMachine中新增region

      state(包括pseudoStatefinalState)之間新增transition

    • 第四輪:

      UML_PARAMETER
      UML_INTERFACE_REALIZATION
      UML_GENERALIZATION
      UML_MESSAGE
      
  4. 容器選擇

    在本單元作業中,主要選用了一下三種容器;

    HashMap
    HashSet
    ArrayList
    
    • HashMap

      主要用於需要檢索的元素集合。

    • HashMap

      主要用於不需要檢索、不允許有重複物件、且在本單元作業涉及到的操作中只需要查詢元素個數或遍歷,不需要檢索或取出特定元素的集合,如類實現的介面、關聯的類或介面等。

    • ArrayList

      主要用於不需要檢索,但在正常情況下(指可以通過第三次作業的檢測且進行查詢時返回資料而非異常)元素個數已知,甚至需要取出操作的集合。

    • 針對依據Name進行查詢的查詢指令所使用的複合容器

      對於一些元素,在初始化時往往需要依據Id來進行識別與查詢,但在處理查詢指令時又需要依照Name進行查詢,且可能因為存在相同Name元素(或不存在該Name的元素)而觸發異常。針對這樣的使用了HashMapArrayList的複合資料結構,以class的儲存為例:

      // DataBase.java
      
      private final HashMap<String, MyClass> classes;
      private final HashMap<String, ArrayList<String>> classIds;
      

      classes中,鍵值為Id,建立了Idclass的包裝類物件的對映;而在classId中,鍵值為Name,建立了Name到一個裝有全部具有該NameclassId的容器的對映。

      由此,在處理查詢指令時,往往可以通過第一級NameId的對映快速判斷是否丟擲異常,如不需要丟擲異常又可以通過第二級Id到包裝類物件的對映快速定位所需要的的資料。

  5. 圖模型儲存

    本單元作業中涉及到了若干個圖,如類和介面的繼承,且需要對路徑、環等進行查詢。

    選擇在包裝類中一方面儲存該節點的邊,即和該節點直接相連的邊,另一方面也儲存所有可達的結點。

    class為例,在其包裝類中即記錄了其由UML_GENERALIZATION所規定的父類和子類,也使用另外的域記錄了其所有父類和子類,這樣的好處是:

    在初始化DataBase步驟便可以計算出全部的所需資訊,在之後處理查詢指令時極少需要迴圈或遞迴操作。

    避免了由於迴圈繼承等錯誤導致陷入死迴圈

    簡化了第三次作業中的檢查步驟


二、四個單元以來各方面理解的演進


  1. 程式設計方面

    從面向過程程式設計到面向物件程式設計的轉變。

    在第二、三和四單元,分別對多執行緒程式設計、JML規格和UML模型進行了一定的瞭解,但同時也在不斷加深對於第一單元內容的理解。

    在進行第一單元時,往往是為了面向物件而面向物件,胡亂分類

    初見面向物件程式設計,不甚理解,只是簡單地將面向過程的程式拆成三個檔案,裝到三個類中

    類的架構設計完全依據直覺和程式碼長度,沒有從層次和功能考慮

    錯誤地認為物件只能是一種事物,無法理解將某種操作定義為一個物件的行為

    由此導致寫出來的程式有著拓展性極差等缺點,最終在第三次作業時體驗了通宵重構的快樂

    在進行第二單元時,過於極端地執著於拆分

    由於重構的慘劇就在昨日,過分地關注物件的拆分,三四個類即可完成的第一次作業被拆到了13個類ORZ

    類的設計過於零散,甚至存在部分不必要單獨列出的純方法類,本質上還是殘留的面向過程程式設計思維所致

    資料結構的設計沒有被重視,一方面導致想象中極佳的拓展性(w)並沒有很好地體現,反而受到了重重製約;另一方面也突出了類的設計的缺陷:資料與方法的割裂,導致部分資料在不同的物件之間被反覆拷貝,效率低下

    在進行後兩個單元時,逐步注意到了上面的問題,努力地改正,但仍有需要提高的地方:

    相似結構的程式碼反覆出現,沒能很好地進行程式碼的複用

    類的架構設計仍不甚合理,尤其表現在主幹類中行數過多、功能駁雜,給程式編寫帶來了諸多不便。

  2. 測試方面

    graph LR Z[程式的測試] A(樣例) --> B(大量隨機資料) B --> C(單元測試) B --> G(大量特殊重複資料/指令) B --> D(臨界資料) D --> E(資料限制) D --> F(程式語言限制) E --> H(正確性測試) F --> H C --> H G --> I(效能測試)

    最初並不是很能理解測試的重要性,錯誤地認為“自己造資料時注意到的可能會出錯的地方,自己在當初編寫程式時一定也會注意到”,覺得編寫測試資料和重新閱讀原始碼檢查的作用相仿,並沒有重視

    後來逐漸認識到了使用大量的隨機資料可以快速發現編寫程式時忽略的邏輯錯誤,尤其是在進行互測,面對並非由自己編寫的程式時。

    由此自然想到針對程式語言的限制和資料自身的限制進行鍼對性地測試。在編寫程式時往往是從解決問題的角度出發,容易忽略掉特殊的情況,而測試時卻可以轉換角度,從資料本身出發,從而更有針對性地檢驗特定的問題。

    在後兩個單元中,學習了單元測試的測試模式,簡化了測試的難度,提高了測試的針對性。同時在此也首次將注意力放到了效能問題上。


三、課程收穫


  1. 面向物件程式設計的相關知識。

    這自不必多言,課程核心所在。

  2. 熟練使用 java 語言。

    在課程之前我對這門程式語言的瞭解僅限於上學期《java程式設計》課程期末考試之前的三天速成,經過這一學期的磨鍊,已經熟練掌握了這門語言的基本應用。

  3. 懂得了關注架構設計

    這是程式設計方法上的提高,具體上面已經有了詳細地說明,但其實這並不只是面向物件程式設計獨有的思維模式,在目光重新回到用C語言編寫面向過程的程式時也有了更加清晰的思路,甚至也在影響著其他的領域。

  4. 更加註重程式碼風格


四、課程改進建議


  1. 上機實驗反饋

    個人認為上機實驗的題目也是需要反饋的,尤其是部分上機實驗的題目與課下作業的形式有較大不同,這也是同學對自己是否理解了課上內容的一次檢驗

  2. 互測指導

    課程組多次強調參與互測的重要性,但個人認為與之配套的更加詳細的指導也是需要的,包括但不限於相關工具的使用、評測機的搭建等,甚至可以考慮將搭建一臺評測機作為一次課下作業的內容2333

  3. 時間略顯緊張

    影響我本人互測積極性的另一大因素便是沒有充分的時間進行互測,只有一兩天的時間,週二還是滿課emmmm,雖然互測不結束就沒有辦法進行後續的debug等環節,但將每次作業的週期再延長一週左右或許也無傷大雅?


最後,感謝課程組的老師和助教們,

以及身邊一直給予了我諸多幫助朋友們,

希望OO課程可以越辦越好,

希望大家都能取得滿意的成果~

2021年6月26日