BUAA_OO第四單元總結(類圖)
1. 架構設計
1.1 第一次作業
第一次作業要求實現UML類圖的查詢功能。在維護類圖的時候,採用了以類(Class)為結點的構建方法,即將Class處理成以鍵值對<\id, Class>儲存在HashMap中。將類圖中的其他元素看成是Class中的屬性,這樣能夠更好地進行層次化的類圖構建。
關於層次化,本次架構按照層次,共有如下幾類:
- MyUmlGeneralInteraction:實現了介面UmlGeneralInteraction,是各類查詢功能的入口
- MyModelGraph:類圖類,用於構建和維護類圖,其中如下元素:
- MyClass
- MyInterface
- MyClass:儲存類的各種屬性和關係,有如下元素:
- UmlAttribute:儲存類的屬性
- MyOperation:儲存類的方法
- UmlAssociationEnd:儲存類的關聯關係
- MyInterface:儲存類實現的介面
- MyClass:儲存類的父類
- MyInterface;儲存介面的各種屬性和關係,有如下元素:
- MyOperation
- UmlAssociationEnd
- MyInterface:儲存介面繼承的介面
- MyOperation:儲存方法,有如下元素:
- UmlParameter:儲存方法的引數
- UmlParameter:儲存方法的引數
至此,類圖的所有資訊都以層次化的方式儲存到了MyUmlGeneralInteraction。
關於採用的資料結構,觀察實現的功能,其中ClassNotFoundException, ClassDuplicatedException,AttributeNotFoundException, AttributeDuplicatedException等異常的處理,以及相關的查詢是以類,屬性等的名稱來進行查詢的,而在類圖中是以id作為唯一標識的,因此需要以id來進行儲存。而這樣會導致以name查詢名稱重用,名稱是否存在,取得相應元素,效率很低。因此考慮將name和id進行維護,在查詢的時候將name轉換為id。
為此,在實現上,為Class,Interface,Attribution等元素維護了HashMap<\String, ArrayList<\String>> nameMap,用來將組成name和id的一對一至一對多對映,方便異常判斷,並可以將name轉換為id,在以id為鍵值的HashMap中方便地取得元素。
在關聯關係的表示上,採用在Class或Interface中維護對端的UmlAssociationEnd來進行表示的,而UmlAssciation只是用來明確UmlAssociationEnd應該向哪個結點分配。
同時,由於採用的是層次化的類圖構建,而讀取到的Uml元素可能並不是按層次化的順序,因此可能出現,一個更底層的元素所依賴的上層元素還沒有出現時,需要儲存這一底層元素的情況,出現空指標異常。在類圖即MyModelGraph初始化的時候是按照層次由高到低一層一層進行初始化的:
- 首先初始化類圖結點MyClass和MyInterface,另外初始化MyOperation儲存到相應結點,UmlAssociationEnd方便後續使用
- 初始化UmlAttribution儲存到結點中,初始化UmlParameter儲存到MyOperation,讀取UmlAssociation以儲存上一層的UmlAssocationEnd到結點,讀取UmlInterfaceRealization,UmlGeneralization儲存相應的MyClass,MyInterface到相應的結點。
1.2 第二次作業
第二次作業實現了時序圖和狀態圖的查詢,依然採用了層次化的構建方式,在時序圖中以UmlLifeLine為結點,在狀態圖中以UmlState為結點,維護了圖
關於時序圖層次化:
- MyUmlGeneralInteraction:實現了介面UmlGeneralInteraction,是各類查詢功能的入口
- MyInteractionGraph:時序圖類,用於構建和維護時序圖,有如下元素:
- MyInteraction
- MyInteraction:儲存和維護每一個互動圖,包括:
- MyLifeLine
- MyLifeLine:互動圖的結點,包括:
- UmlMessage
在實現上,依然採用了資料結構HashMap<\String, ArrayList<\String>> nameMap,方便查詢和異常處理
- UmlMessage
關於狀態圖層次化:
- MyStateGraph:狀態圖類,用於構建和維護狀態圖,包括:
- MyStateMachine
- UmlTransition
- MyStateMachine:狀態機類,包括:
- UmlPseudostate:起點狀態
- UmlFinalState:終點狀態
- MyState:狀態結點
- MyState:狀態類,包括:
- UmlFinalState
- UmlPseudostate
- UmlEvent
- UmlTransition
為了方便查詢演算法對所有狀態的統一管理,將起點和終點統一交給了Mystate來管理,實現了三個過載的初始化方法:
public MyState(UmlState state, HashMap<String, UmlTransition> transitionMap)
public MyState(UmlFinalState umlFinalState, HashMap<String, UmlTransition> transitionMap)
public MyState(UmlPseudostate umlPseudostate, HashMap<String, UmlTransition> transitionMap)
實現上同上。
1.3 第三次作業
這一次主要是對所構建的類圖進行合法性檢測。這一單元的作業,層次化相對容易,同時考慮到了可擴充套件性的問題,在每個層次中的類中維護了足夠多的資訊,因此在檢查合法性上,相對容易,主要在迴圈繼承,重複繼承方面需要謹慎考慮。總之是三次作業中最容易的一次。
2. 四個單元中架構設計及OO方法理解的演進
2.1 第一單元
層次化這一單元,第一次接觸到了面向物件構造,這一單元給人留下了非常深刻的印象,現在回看,這一單元的難度也是很大的,由於巢狀等形式的存在,使得這一單元的層次化工作相對難以實現。
在最初第一次作業的時候,思維依然沒有跳出過去面向過程的程式設計方式,只是將過去按照函式進行封裝改為由類進行封裝的模組化設計,這也導致了在第二次作業的時候進行了面向物件所有作業中最痛苦的重寫。
而在之後的作業中,慢慢感覺到了面向物件中實現,繼承和多型的特性,對於這些特性的運用,初步感受到了面向物件的便利。
總的來看,本單元的作業,由於第一次接觸到面向物件的思想,並不瞭解架構為何物,所以也沒有考慮太多架構設計。類與類之間的耦合是非常緊密的,同時採用了大量的反射特性和if-else級聯,其實返回來閱讀是很痛苦的lol。
本單元對OO方法的理解,也許就停留在了利用面向物件的語言特性,簡化編碼(硬編碼)。以及通過類進行封裝,達到模組化設計
2.2 第二單元
這一單元進行的是多執行緒程式設計,作為多執行緒死鎖選手,debug的過程是非常痛苦的,尤其是第一次不知道多執行緒除錯需要檢查哪些問題,也不知道JProfiler等工具的運用,一個鎖順序問題,可以卡一天。
但是,其實本單元最重要的內容是關於架構方面的設計,課堂上講授了生產者消費者模式,發現設計模式對於架構設計可以提供非常好的實踐,所以在課下也學習了其他模式,例如介面卡和單例模式。
本單元由於多執行緒的存在,各個模組的時間線和功能都是獨立的,耦合度相比第一單元低了很多,因此很方便理解面向物件設計。
本單元對OO方法的理解,有了一些自己的理解,作業中有生產者,托盤,消費者,它們之間具有自己獨立的功能,維護自身的資料結構,對於其他類僅僅暴露自己少量的介面,以實現解耦,達到良好的擴充套件性。
2.3 第三單元
這一單元的JML,讓我有了架構優先於程式碼編寫的認識,對於一個工程,首先需要有明確的需求,其次要由架構設計自頂向下地進行模組的規劃,考慮每一部分地功能以及可擴充套件性,而忽略使用的資料結構和具體的方法。最後,在我自己填充提供的框架的時候,深感對於具體程式碼的填充採用自底向上的方式,可以更加方便地考慮自己要採用的資料結構。
2.4 第四單元
這一單元的UML類圖,自己在前面三次作業中對層次化有了新的認識,因此從一開始在編碼的時候,無論是資料結構還是架構,都在考慮隨後的可擴充套件性。生成的UML類圖,相比之前,肉眼可見的順眼(有了層次)。
3. 四個單元中測試理解與實踐的演進
在測試方面的演進主要集中在第一單元上,這一單元非常迷信於自動化的隨機測試,以為測它個上千上萬次就萬事大吉了。但是由於採用的是隨機測試,而在測試中覆蓋率才是最重要的影響因素,對於極端資料幾乎難以進行有效覆蓋,因此互測中被各類奇怪的資料進行了Hack。
而後來對極端資料,主要是手動生成,但是這種方式難以對程式做到100%的覆蓋率。
另一方面,為了儘量將bug扼殺在搖籃裡,減少在最終測試中隱藏的蟲子,Junit可以對方法,模組進行覆蓋測試,減少了模組內部的bug,能夠有效加快測試速度,錯誤率也會低很多。但是自己在編寫測試的時候,需要仔細考慮,由於這一點,對所有的模組,方法都進行覆蓋測試,是不現實的,需要首先篩選出演算法複雜之類的模組,進行測試,同時兼顧效率和準確率。
而在大的方面,所有的OO作業都主要以python進行測試資料生成和對拍。python提供的大量庫可以儘量保證python實現功能的正確性。
4. 課程收穫
首先,在截止目前的所有程式設計相關的課程中,面向物件的課程體驗毋庸置疑是最好的,課程和作業緊密相關,每個單元都有一個聚焦的重點。
面向物件設計與構造,首先最重要的一點就是面向物件的思想,在課程過程中,從面向過程的程式設計思想,逐漸過渡到了面向物件的程式設計方法,最後發現,其實兩者之間並不是割裂的,在面向物件的過程中,其實面向過程的方式可以用於在模組內部方法的層次化
另一方面,就是設計與構造了,課程讓我開始逐漸知道在實際實踐過程中,架構設計才是其中更加重要的一方面。合理的模組和層次設計不僅可以滿足良好的可擴充套件性,另一方面其實也可以簡化程式碼的工程量。
其次,在最後一個單元的官方包裡的pom.xml引起了我的注意,在查詢以後才知道這是Maven的配置檔案,因此也去學習了一些關於Maven專案管理的內容,通過學習,不僅可以將Junit,打包等工作統一起來。更重要的一點是Maven可以把java很多內容串起來,給面向物件或java的進一步學習提供了一個方向。
5. 改進建議
面向物件的課程設計相比其他課程已經比較完備了,如果有建議,大多就是些小修小補:
- 可能在學習曲線上還是稍微有一些陡峭,第一二次作業的難度和其後兩次作業的難度,形成鮮明的對比。我覺得可以考慮將一部分多執行緒和層次化的具體實踐下放給一個預習模組,或者在預習模組提供一個實踐例子,先試試水(
- 在預習上,也可以提供一些關於測試的設計練習
- 作業和訓練都有良好的反饋機制,是否可以考慮實驗提交或者結束以後給一個反饋,方便知道自己的問題。