BUAAOO Unit4:UML總結
BUAAOO Unit4:UML
目錄1. 本單元的架構設計
1.1 第1次作業
UML層次圖
- UMLInteraction
- UMLClass
- UMLAttribute
- UMLOperation
- UMLParameter
- UMLAssociation
- UMLAssociationEnd
- UMLInterface
- UMLGeneralization
- UMLInterfaceRealization
- UMLClass
具體實現
初始化
在讀入類圖的各個元素後,要把類圖的相應元素“匹配”到相應的層次,就如上面的UML層次圖一樣。除了上面的一些屬性,需要注意的是每個Class有他繼承的父類(如果有的話),每個Interface也有他繼承的介面。所以我們可以根據上面這個層次圖把每個class和Interface的性質都“設定”好。比如:把InterfaceRealization對應到class和interface的實現的介面
parent
;把Generalization對應到class和interface的parent
。
函式功能
本次作業要求實現的函式功能都比較簡單,對於屬性attribute的查詢基本上都是要考慮繼承關係,這時可以在Generalization
初始化時,在每個class中,根據其繼承關係(單繼承)設定一個parent(UMLClass),方便沿著繼承關係向上找各個父類。
UML圖
可能出現的bug
要讀懂題意,判斷查詢操作是否應該考慮繼承關係
1.2 第2次作業&第3次作業
UML層次圖
- UMLClassModelInteraction
- 同上次作業的Interaction下的架構
- UMLCollaboration
- UMLInteraction
-
UMLMessage
-
UMLLifeline
-
- UMLAttribute
- UMLInteraction
- UMLStateChartInteraction
-
UMLRegion
-
UMLPseudostate(InitialState)
-
UMLFinalState
-
UMLState
-
UMLTransition
-
UMLEvent
-
UMLOpaqueBehavior
-
-
-
第3次作業新增的合法性檢查並不影響第2次作業中的查詢演算法的實現。
具體實現
UMLCollaboration
- 關於Attribute
- 因為類圖裡面也有Attribute,所以需要區分attribute是屬於類圖還是屬於順序圖的。我的處理是先初始化類圖,在初始化類圖的時候,需要把attribute對應到相應的class和interface裡面,所以沒有對應上的attribute就是屬於順序圖的,把這些attribute放到一個list裡,再傳給順序圖
- 在對
IncomingMessageCount
和sentMessageCount
- 我在將每個
message
對應到interaction
的時候就設定了兩個表 - 一個是用
HashMap<String, Interger> name2inMesCount
來記錄incomingMessage,前面的String是Message的target name,後面的Integer是message的數量。 - 一個是用
HashMap<String, HashMap<MessageSort, Integer>> name2sentMes
,第一個String是message的source name,後面的Integer是每個MessageSort型別對應的message數。 - 注意到這兩個都是關於name和他們別的屬性的對應,所以有可能有重名的lifelineName,這個時候先檢查下這個name的lifeline是否唯一,如果不唯一就丟擲異常即可。
- 我在將每個
UMLStateChartInteraction
subsequentCount
- 記錄一個狀態可以到達的所有狀態數(包括直接到達和間接到達)
- 我的處理是對於一個狀態,先把他能到達的所有直達頂點放到一個queue和map中,然後當queue不為空時,彈出一個元素,把它的所有直達頂點放到queue和map中(需要保證和原來在queue和map中的元素不重複),如此迴圈,直到queue為空,此時map的size就是所要求的的狀態數。
findTransitionTrigger
- 找到一個狀態A到狀態B的所有觸發事件
- 我的處理是在將Transition對應到Interaction時,先用一個
tranId2Id
來記錄id1到id2的所有Transition(一個ArrayList),然後在查詢時把這個ArrayList<Transitition>遍歷,把每個event放到一個List裡,最後返回。
StandardPreCheck
- R002\R003\R004:採用BFS演算法,沒有進行優化(也沒有T掉,萬幸)
- R005、R007:我都是設定了一個變數,在初始化的時候就檢查,比如說R005:我設定了一個
boolean isNullValid
,在初始化的時候,遇到UMLClass、Interface、operation、direction不為return的parameter、還有類圖中的attribute,當name為null時,將這個isNullValid
置為true,然後返回,避免了查詢時再對這些元素訪問
UML圖
可能出現的bug
在初始化的過程中,有可能會訪問空指標,需要注意。
2. 四個單元的架構設計以及OO方法理解的演變
2.1 Unit1:多項式求導
多項式求導屬於“開屏暴擊”,由於我本身對Java就很不熟悉,再加上假期沒有做pre,導致前三週我的作業都完成的十分匆忙,而且基本上都是在用面向過程的思想在實現,導致每一次的“迭代開發”都變成了重構,達成“三次作業,兩次重構”的成就,直到第三次作業才開始慢慢地摸到門道。
第一次作業面向過程的影子很明顯,在Expression
和Term
中都有很長篇幅的解析字串的程式碼塊,使得整個程式碼非常臃腫。而且我的程式碼只是面向第一次作業程式設計,並沒有使用任何的繼承,字串的預處理和解析都在一個模組完成,並沒有根據方法的功能嚴格劃分各個方法,每個類的功能很複雜,並沒有實現單個方法單個任務,類“形同虛設”,預示著我下次作業的重構。
第二次作業中沒有使用遞迴下降法來解析表示式,而是使用表示式樹,對下一次作業的風格檢查和sin、cos裡面套表示式無法適用,沒有很好的擴充套件性。
經過這兩次重構,我決心從下一次作業開始,好好設計架構,避免重構。
2.2 Unit2:電梯
這一單元吸取了上一單元重構的教訓,我從在每次作業前都會提前打好草稿,想清楚自己要設計哪些類,每個類的功能都各自是什麼,減少類與類之間的耦合,每個類實現的功能要單一。比如說主執行緒和讀入執行緒分開,讀入執行緒只負責讀入和把請求放到緩衝區,主執行緒負責對類例項化和啟動各個執行緒我將電梯的自身執行(例如開關門、到達、進出乘客)這些事都扔給了Elevator
執行緒自己去做,即Elevator
只管電梯的執行輸出和進出人。把決定執行緒是否開關門、是否進出乘客、改變執行方向等這些事都丟給了Scheduler
去做,即Scheduler
管電梯自身的排程演算法。
2.3 Unit3:JML
這一單元相對前面兩單元難度是跳崖式變化,函式的功能可以根據JML規格來判斷,這一單元的第一次作業主要是讀懂JML規格的含義,瞭解JML規格的寫法和一些語法,到後面兩次更偏重於優化演算法、選擇什麼樣的容器和演算法能讓用時最少。
2.4 Unit4:UML
我仿照課程組給的jar包的架構,把自己實現的類分成了Element和Interaction兩部分,這一單元的第一次作業我覺得還挺難的,畢竟從0到1總比從1到2難,看了很多UML的東西但感覺都跟課程聯絡不大,後來我思考了一下,主要是我們的解析各個UML模組,主要是要建立UML的樹層結構(第一部分裡列出的),在每個自己實現的類中建立好所屬關係,比如說每個UMLClass有很多個Attribute,有很多個Operation,每個Operation裡面有很多個Parameter這樣。第二次作業新增的Collaboration和StateChartInteraction也是如法炮製,對於合法性檢查,也是獨立於這些函式的功能之外的,只需在原有基礎上在初始化時順便檢查或者後面遍歷檢查。
3. 四個單元中測試理解與實踐的演進
-
形式化驗證
在JML單元顯得比較有效,對照JML規格進行形式化驗證。我是先根據JML規格把規格“翻譯”成自然語言,然後檢查自己實現的程式碼是不是這樣。因為有的時候寫著寫著就可能“多幹一步”、或者“少幹一步”,出現難以發現的bug,所以我認為對照JML進行驗證算是不錯的查詢bug方法。
-
單個函式單獨測試功能
- 因為我不太會寫自動評測機,所以就只能手動構造資料了,基本上把能想到的一些情況都測了,但還有一個注意的地方就是,我有的時候是直接跑而不是debug模式,所以有些時候雖然結果是正確的,但可能多刪了一些東西、或者少刪了一些東西,在後面測試的時候才發現這個問題。
-
整合測試
- 這一部分主要與前面的測試相對,除了單獨測試每個函式的功能外,還要生成覆蓋面較廣,對整體功能進行測試的用例。測試用例既要有普遍的,也要有專門針對優化演算法設計的,數量要足夠多。
-
Junit測試
- 對於JML單元和UML單元來說,是一種比較好的測試方案
4. 課程收穫
OO課程真的挺痛苦的,但收穫也是很多的。比如說掌握了一門語言JAVA,瞭解了多執行緒、JML規格的寫法和表示,UML元素以及UML圖,瞭解了遞迴下降法等,最重要的就是面向物件的設計思想,面向過程和麵向物件都有各自的好處,在一開始(好像現在也是這樣)我對“類”的理解是C語言的結構體plus,除了定義各個變數還能寫函式。但其實,如果要我說出“面向物件”的具體思想的話,我也說不出什麼比較官方的話,我個人的理解就是把一個功能的實現下發給不同的“個體”,每個“個體”有自己的”屬性“,可以有自己的“處理方法”(函式),相當於平日生活中的“責任到人”。這一學期的OO課,雖然累但是真的收穫了很多,一開始接觸這門課的時候感覺真的要難死了,第一單元都不知道從何下手,但隨著每次作業的下發、構思、和同學間的探討,我也慢慢地摸到了門路,能夠從容應對每次作業,OO課程完結撒花。
5. 改進建議
-
作業
- 在每一單元的第一次作業後面可以寫一下第二次作業和第三次作業主要都擴充套件什麼內容,這樣能夠方便更好地想好架構(比如說第一單元如果知道後面要格式檢查的話,可能在第一次就會開始上手遞迴下降,雖然說遞迴下降法不是作業的必須採用的方法)
-
上機
- 每次上機都不知道自己的成績到底怎麼樣,如果可以在實驗後公佈上機成績就好了。
- 如果上機的程式碼閱讀量比較大,或許可以提前半小時或者一小時開放程式碼庫,讓大家先閱讀下程式碼,理解一下每個類實現的功能,比如說有一次實驗是關於Java的垃圾回收機制,那次程式碼真的是又多又難,實驗課時間又短,想要短時間內讀懂程式碼又補全一部分功能的程式碼的話實在是有點困難