1. 程式人生 > 其它 >BUAA_OO第四單元總結

BUAA_OO第四單元總結

BUAA_OO第四單元總結

架構設計

第一次作業

第一次作業主要是針對對類圖資訊的查詢。首先,由於\(UmlElement[]\)中資訊並不按順序,即一條資訊的父節點並不一定下標小於此條資訊。因此我進行了多次迴圈遍歷\(UmlElement[]\),在每次迴圈遍歷的過程中獲得相應類別的UmlElement。

在建立各類類別的UmlElement的聯絡過程中,我主要是考慮了各類UmlElement的父節點的類別和查詢類圖資訊指令的情況,採用了一下的結構:

  • UmlClass
    • UmlAttribute(s)
    • UmlOperation(s)
      • UmlParameter(s)
    • UmlAssociation(s)
    • UmlInterface(s)
    • UmlClass(父類)
  • UmlInterface
    • UmlOperation(s)
      • UmlParameter(s)
    • UmlInterface(s)(父類)

此外,為了建圖時查詢父節點的id方便,我多數採用了以其id作為key,其本身作為value的HasMap結構,例如HashMap<String, MyClass> classesHashMap<String, MyInterface> interfaces,那麼在UmlClass和UmlInterface下的節點在建圖時便可以通過以父節點id作為索引進行查詢,較為方便。

第二次作業

第二次作業增加了對狀態圖和順序圖的資訊查詢。設計思路與第一次作業相似,以各類UmlElement的父節點的類別和查詢類圖資訊指令的情況作為切入點,我採取了以下架構:

狀態圖:

  • UmlStateMachine
    • UmlRegion
    • UmlElement(s)(UmlPseudostate/ UmlFinalState/ UmlState)
      • UmlElement(s)(UmlPseudostate/ UmlFinalState/ UmlState)(直接後繼)
    • UmlTransition(s)
      • UmlEvent(s)

狀態圖比較困難的是\(getSubsequentStateCount\)

\(getTransitionTrigger\)\(getSubsequentStateCount\)介面的實現主要通過每一個狀態都儲存了的直接後繼狀態實現,通過DFS進行對圖的遍歷(標記已經遍歷過的點)獲取所有遍歷過的點即為所有可到達狀態。\(getTransitionTrigger\)介面的實現主要是通過獲取所有同名的UmlTransition,然後再獲得其所有的UmlEvent,邏輯較為簡單。

順序圖:

  • UmlInteraction
    • UmlLifeline(s)
      • UmlMessage(s)(生命線接受的資訊)
      • UmlMessage(s)(生命線傳送的資訊)

順序圖的介面功能較為簡單,在UmlLifeline下分類儲存接受的資訊和傳送的資訊即可。

此外,我還將MyUmlGeneralInteraction分成了三類:MyClassDiagramManagement、MyStateDiagramManagement和MySequenceDiagramManagement分別負責類圖、狀態圖和順序圖的管理。

第三次作業

第三次作業為糾錯,功能都較為簡單,比較複雜的介面都可以通過DFS進行解決,比如迴圈繼承可以通過DFS獲得其所有的父繼承然後判斷其本身是否在裡面;重複繼承可以通過DFS,如果在遍歷的過程中出現了重複則返回一個true,否則為false。

此外,糾錯的介面我分別放置在了負責類圖、狀態圖和順序圖的管理類裡面。

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

第一單元

此單元是初識面向物件。現在回想起來,我對這個單元認識最深的應該是類的繼承和多型的實現。採用二叉樹的形式儲存多項式,其中涉及的類包含加法表示式、乘法表達式、三角函式等等,所有的類都繼承自抽象類Expression,並實現toString、求導等方法。求導方面,由於我採用了二叉樹的結構,所以求導為遞迴呼叫即可。

在完成第三次作業以後,在與同學討論以後,認為二叉樹在長度優化方面比較困難,其一要進行許多的類判斷(比如合併常數時要判斷是否是Constant類,如果加式裡其中之一是加式,又要進行對內加式的兩個加式進行型別判斷,極其困難),其二就是化簡和換位置要進行樹的遍歷的操作。因此,二叉樹結構在功能實現方面有比較大的優勢,但在優化方面不夠好。

第二單元

此單元是多執行緒的設計。我覺得難點主要是架構設計和執行緒安全設計,我的架構(第三次作業)主要為讀取執行緒、排程器執行緒、多個電梯執行緒(電梯策略我使用了類似look的演算法)和回收執行緒。讀取執行緒負責讀取乘客資訊,傳遞給排程器;排程器執行緒負責分配此乘客至匹配度最高的電梯;回收執行緒負責把電梯送出的乘客回收至排程器(在排程器裡進行進一步的查詢:如果到達其目的樓層則將乘客移除,否則繼續分配此乘客)。在此架構中,我一開始設計出現了環形死鎖問題(有點像哲學家就餐問題),在與同學的討論過後,我將流程比較簡單的回收執行緒設定成了守護執行緒保證了執行緒資源之間不會成環。

第三單元

此單元是JML形式化描述的學習以及程式碼實現。我覺得這個單元是最為輕鬆的。只要按照閱讀介面的規格,確定合適的容器,選擇合適的演算法這個流程實現每一個介面,基本都沒有什麼問題。比較坑的點我覺得是和\(queryBlockSum()\),可以通過並查集實現查詢是否在於同一個連通塊的操作,除此之外還有堆優化的迪傑斯特拉最短路徑。

第四單元

第四單元的架構設計如上所示,其架構設計我主要從各類UmlElement的父節點的類別和查詢類圖資訊指令的情況方面入手的,設計起來也較為方便。

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

第一單元

第一單元的測試主要是手動極限資料測試和評測機隨機資料測試。評測機隨機資料測試一般用於測試是否存在顯而易見的bug,手動測試則採用不斷巢狀函式、括號等方式測試程式的效能。

第二單元

第二單元的測試主要是手動構造(評測機的評測正確性並不會實現)。我仍記得在第三次作業中主要嘗試了n個乘客從4樓到20樓的較為極端資料。

第三單元

第三單元的測試主要是針對某一個介面構造極限資料和與同學的對拍測試。與同學的對拍測試保證基本功能不會出錯;針對某一個介面構造(例如圍繞並查集和最短路徑演算法進行邊界測試)主要測試TLE方面的問題。

第四單元

第四單元臨近期末只在第三次作業中進行了對迴圈繼承和重複繼承/實現的手動資料構造測試。

總體上講,我主要採用了

  1. 手動構造邊界資料測試(針對編寫時出現的思維慣性錯誤和程式效能不良)
  2. 測評機隨機資料測試(主要測試出理解不當或實現不恰當的bug)
  3. 對拍測試(同上)

課程收穫

經過此次面向物件課程,我個人感覺收穫滿滿。

  1. 深化對面向物件的認識,更加關注各種類和類的功能,在程式設計時養成從各種類和類的功能的層面關注問題的思考方法。
  2. 習慣從程式的拓展性方面思考問題。多項式求導和電梯這兩個單元的重構設計現在回顧過來仍然頭皮發麻:往往都是在第二次作業中減少了對拓展性方面的思考而撲街。
  3. 學習了面向物件基本的繼承、多型、介面等特徵。每一個單元都有自己的主題:繼承和多型、多執行緒、JML、UML,並且從零學習了Java語言的語法和使用,在後面的課程中逐漸熟悉了Java各種高效的操作。

立足於自己的體會給課程提三個具體改進建議

  1. 上機實驗能否給出評測結果或者分數。
  2. 指導書方面希望可以更加準確一點(第一單元雖然形式化符號可以表達出可以出現三個符號,但是文字描述方面是不行的)
  3. 第四單元第一次作業可以給予更多的關於程式實現方面的提示(這個單元雖然較為簡單,但是第一次作業我真的不知道要實現什麼)。