OO第四單元部落格總結
第二單元部落格作業
本單元的架構設計
本單元的三次作業都是對UML圖進行的解析,測試內容並不複雜,重點是理解每個UmlElement
所處的層次和關聯。
對UML元素的儲存結構
private HashMap<ElementType, ArrayList<UmlElement>> elements = new HashMap<>(); private HashMap<String, UmlElement> elementsMap = new HashMap<>(); private HashMap<String, MyUmlClass> classes = new HashMap<>(); private HashMap<String, MyUmlOperation> operations = new HashMap<>(); /* other elements stored in HashMap<> using id as key */
在解析器核心類中首先對讀取的UmlElement
進行儲存,按照類別儲存在不同的容器中,elements用於第一遍的分類,之後根據需要遍歷對應的連結串列,對元素之間的關係進行新增。
for (UmlElement element : elements) { elementsMap.put(element.getId(), element); this.elements.get(element.getElementType()).add(element); if (element instanceof UmlClass) { classes.put(element.getId(), new MyUmlClass((UmlClass) element)); } if (element instanceof UmlOperation) { operations.put(element.getId(), new MyUmlOperation((UmlOperation) element)); } } /* ... */ for (UmlElement operation : this.elements.get(ElementType.UML_OPERATION)) { if (classes.containsKey(operation.getParentId())) { classes.get(operation.getParentId()).addOperation( operations.get(operation.getId())); } } /* ... */
對UmlElement的擴充套件
由於UmlElement之間存在大量的繼承與實現關係,簡單的新建子類並繼承UML類並不能滿足需要,並且往往帶來重複繼承的問題,同時我們又需要自己的類之間存在聯絡,因此我採用了下面的方法。
public class MyUmlClass { private UmlClass umlClass;//原有UML元素成為MyUml的一個屬性 private ArrayList<UmlAttribute> attributes = new ArrayList<>(); private ArrayList<MyUmlOperation> operations = new ArrayList<>(); private ArrayList<String> associations = new ArrayList<>(); private ArrayList<String> interfaceList = new ArrayList<>(); public MyUmlClass(UmlClass umlClass) {//借用原有元素進行初始化,這一步恰好能在解析器初始化的時候一起完成 this.umlClass = umlClass; } public UmlClass getUmlClass() { return umlClass; } public void addAttribute(UmlAttribute attribute) { attributes.add(attribute); } public void addOperation(MyUmlOperation operation) { operations.add(operation); } public int getOperationCount() { return operations.size(); } /* ... */ }
第三次作業UML圖
首先需要指出的是,由於程式碼規範要求,解析類不能過長,於是初始化的部分被迫分散到了三個類中,分別是MyUmlGeneralInteraction
、MySecClass
、MyThirdClass
。初次之外,由於類圖部分在後兩次作業中幾乎沒有變動,我出於偷懶的心態一直沒有建一個單獨的MyUmlModel
,使得這一部分略顯醜陋。
實際上,時序圖部分通過MyCollaboration--->MyUmlInteraction
的架構,狀態圖部分通過MyUmlStateMachine--->MyUmlRegion--->MyUmlState MyUmlTransition
的架構,加之我沒有建的MyUmlModel
類,足以完整的解釋三種UML圖,並符合原有的繼承實現關係。
四個單元中架構設計及OO方法理解的演進總結
-
第一單元表示式求導
按照不同因子建立了不同的類進行儲存,並且建立了抽象父類
Factor
,每個因子都覆寫求導方法和toString方法,其中類的建立主要是按照自然語義進行的劃分,足夠滿足作業要求。對於解析表示式的方法,我從第二次作業開始採用了遞迴下降分析方法,在第一次作業裡使用的是正則表示式解析,考慮到迭代開發的複雜程度和效能要求,正則表示式的方法很快就被拋棄了(誰都不想寫讀行100多個字元的匹配式不是嗎) -
第二單元電梯多執行緒
這一單元迭代開發實現的比較好,排程器與電梯分離,排程器考慮排程演算法,即將請求分配給哪個電梯;而每個電梯只需完成本單元第一作業的工作即可,這樣可以方便的改變單個電梯的排程策略,或者排程器的排程策略,也有了一些層次化、模組化的思想。但是由於對電梯排程方式的思考不足,第二次作業想當然的選了集中排程思路,結果強測大崩盤。這一單元裡遇到的執行緒安全問題比較考驗思維能力,但其實只要在寫程式碼之前想清楚哪些是共享資源就可以了,按照多執行緒程式設計模式寫,不會有問題的。
-
第三單元JML規格
這一單元的架構幾乎是按照官方程式碼來走的,所需要做的只是建立必要的儲存容器進行快取,但是這並不意味著完全翻譯規格。其實在平時書寫程式碼的過程中一般也會盡量避免使用List儲存,畢竟在大量資料儲存中這種結構效率極低,讀完JML規格之後很明顯就能看出這是人際關係網路的模擬,再加之眾多
elem
的Id是獨一無二的,肯定就使用HashMap<>結構儲存了。在這一單元裡出現了很多有關圖查詢的演算法,多采用快取思想進行效能優化會有驚喜。 -
第四單元UML解析
這一單元的架構是按照Uml元素的層次關係構建的,使得元素間建立由高到低的儲存關係。具體架構上文已經給出,這一單元最重要的工作量是在理解UML規格上,但是經歷了一個學期的程式碼書寫,好多關係一看就能明白了,選擇一個好的儲存結構就可以開始寫程式碼了。
總的來說,所實現的程式碼越來越有層次和邏輯了,有一定的擴充套件能力,初步達到了迭代開發的要求。好的架構的特點是簡潔、清晰、高內聚、低耦合、易維護、可擴充套件,這也是OO方法中很重要的一部分。一開始對於類的劃分可能是根據語義,但隨著對物件互動關係的理解深入,好的架構需要讓每個類或方法都應只有一個明確的職責,只管理自己該管理的資料。只有做到了這樣,在迭代開發的時候才不會大範圍的修改程式碼,讓迭代變得輕鬆
四個單元中測試理解與實踐的演進總結
除了第四個單元的uml圖實在不知道怎麼測試之外,前三個單元都是通過手動構造邊緣資料+評測機大量隨機資料來測試的。
實際上對於程式碼正確性的檢驗在寫程式碼的過程中就能完成,通過模組化驗證或print輸出的方法可以看出大量的正確性問題;對於效能的損耗,經歷了大量的程式碼書寫也能大概猜測到哪裡是效能下降的重災區,往往通過快取、標記(和換演算法)的方式提升效能,同時可以通過時間戳瞭解各部分的用時;對於多執行緒的驗證往往需要逆向構造測試資料,儘可能的構造衝突點,看程式是否能按預想的思路解決,儘量在編寫程式碼的過程中保持邏輯清晰、頭腦清醒,不要寫出前後邏輯判斷混亂的執行緒行為。
課程收穫總結
JAVA語言我在大一就接觸過,也寫過一些程式,但是對面向物件的思想理解還比較淺顯,對容器的概念也有限。是在預習作業中第一次理解了容器選擇的重要性,以及如何做封裝比較好。在這一學期的繼續學習中,我學到了更多的工程化思想,如工廠模式、觀察者模式還有若干多執行緒程式設計模式等,同時也理解了面向物件的精神核心,給我的程式設計帶來了新的思考方式。另外JML規格和UML圖讓我對程式碼規範有了更深的理解,知道了如何去寫一個清晰易懂的程式碼。
立足於自己的體會給課程提三個具體改進建議
- CheckStyle中的有些設計有些不夠人性,比如每行不超過100詞,每個方法不超過60行,每個檔案不超過500行。尤其是在後兩個單元,每行的字元數往往是因為容器名太長導致的,當然簡化容器名是一個解決方案,但是我覺得把它變成縮寫如
OpIdMap、EleIdMap、IAMap、IFMap
並不能讓人更理解含義,譬如一些英文單詞如Interaction與Interface實在是很難縮寫。方法長度在第四單元和第二單元中出現過問題,一個排程演算法或者解析器初始化方法往往就是要一步步的分析很多的關係,60行有些強人所難。 - 感覺互測有點失去本來的意義了,互測本應該是認真學習他人程式碼,但是6-8人一屋的結果導致了同學們拿著手寫評測機,講重點放在測試而不是相互學習上,我也只有在第一單元看過別人的程式碼,到之後就變成單純的提交資料測評了
- 實驗課讀別人的程式碼的時候真的很頭疼,如果是為了檢測理論課知識,其實完全可以通過選擇填空的方式考察;對於理論應用於實踐的部分,由於已經有了課下作業進行實踐,實驗課是否可以讀一些比較簡短的程式碼或者能對整個程式碼多做一些解釋,否則通過讀程式碼理解別人的架構有點浪費時間,尤其是有時實驗程式碼的架構還沒有那麼符合課下作業的程式碼架構。