OO博客做業2:第5-7周做業總結

(1)從多線程的協同和同步控制方面,分析和總結本身三次做業來的設計策略及其變化。java

第5次做業:多線程電梯算法

基本照搬了課件上「生產者-消費者」模型的設計策略,將InputHandler設計爲生產者線程,將Scheduler設計爲消費者線程,將RequestQueue設計爲托盤。生產者與消費者的工做併發,提升效率。同時,每部電梯設計爲一個線程,由於每部電梯的運行彼此不干擾。InputHandler, Scheduler由主線程建立,三部電梯由Scheduler負責建立,這樣使得調度器能夠獲取電梯的狀態。但這種策略並非最優的。編程

第6次做業:文件監控緩存

這大概是寫得最失敗的一次做業。安全

按課件方法構建了線程安全的SafeFile類。實現了同步化的訪問文件狀態、寫文件方法。然而對於每一個record型請求單獨建一個文件寫入,違背了訓練初衷。多線程

每一個請求設計一個「監控器」線程,直接查看對應文件的狀態,與指導書的設計思路差別較大。這使得程序難以應對path-changed等大規模變化。併發

總的來講,此次多線程之間沒什麼協同可言。同步控制也僅限於對文件狀態的訪問。eclipse

第7次做業:出租車調度測試

此次做業的設計策略基本照搬第5次做業。輸入處理線程爲生產者,調度器線程爲消費者,請求隊列爲托盤。每輛出租車爲一個線程,依然由調度器建立。線程

寫了線程安全的SafeFile類用於輸出文本文件。乘客請求、參與搶單的出租車信息由調度器負責寫入,出租車運行狀況由出租車線程負責寫入,實現了線程協同。

 

(2)基於度量來分析本身的程序結構

1)OO程序代碼度量

第5次做業:

類名 屬性個數 方法個數 代碼規模 main / run方法規模 點評
Elevate_5 0 1 27 17  
Elevator 14 7 176 40 電梯控制邏輯複雜。
Floors 2 4 24    
InputHandler 10 6 158 15 寫得太隨意,不少屬性更適合做爲局部變量。
Request 4   59    
 -CarryRequest 1 3      
 -FloorRequest 1 3      
RequestQueue 6 4 56    
Scheduler 7 8 209 40 保留了上次的調度器代碼。
Tray 3 4 76    

第6次做業:

類名 屬性個數 方法個數 代碼規模 main / run方法規模 點評
Detail 4 3 64    
FileState 4 3 26    
InputHandler 9 6 107   類似的問題
Monitor 8 2 60 30  
SafeFile 2 15 110   爲測試者寫了較多的方法
Summary 4 3 64    
TestDrive 0 1 15    
TestThread          
Trigger 3 8 94   設計有問題

第7次做業:

類名 屬性個數 方法個數 代碼規模 main / run方法規模 點評
_Point 2 7 40    
CHandler 9 4 76 32  
CityMap 4 4 114   算法代碼比較長
FHandler 2 4 55    
Queue 3 3 49    
Request 3 3 24    
SafeFile 2 5 57    
Schedule 6 6 146 44 調度方法夾雜輸出代碼
Taxi 16 9 204 40 運行方法夾雜大量輸出代碼
TestDrive 0 1 18 12  

3)各次做業的類圖

第5次做業:因爲指導書給出了上次電梯的參考類圖,本身的設計基本遵循了指導書。可是Tray這個類沒能發揮出應有的做用,只是單純地緩存請求。更好的作法是同時緩存電梯狀態,電梯運行時更新,調度器須要時讀取。

第6次做業:寫得很糟糕,有「麪條代碼」的嫌疑。對Monitor和Trigger兩個類的職責沒有明確,並且Summary和Detail的代碼有大量重用。

第7次做業:不少地方參考借鑑了第5次做業(多線程電梯)。各個類的職責相對清晰。

4)UML的協做圖(從上到下依次是第5,6,7次做業的圖)

5)設計原則檢查(僅針對第7次做業)

DIP (Dependency Inversion Principle):高層次不依賴低層次。

程序有兩個渠道獲取輸入,一是經過文本文件獲取城市地圖,二是經過控制檯獲取叫車請求。個人程序沒有將這兩種途徑進行抽象和概括,致使程序對輸入方式變化的適應性很差。

命名:

在爲類、實例變量命名時我儘量遵循「顧名思義」,可是走向了另外一個極端。我將一個記錄點信息的類命名爲「Point」,結果後來發現有java.awt.Point這個類,使用GUI時很不方便。無奈之下我將本身寫的類更名爲「_Point」,花了一部分時間更名字。在顧名思義的同時,也儘可能不要取過於簡單、大衆化的名字,不然容易與JAVA類庫重名,形成麻煩。

另外,eclipse建議包名首字母小寫,類名首字母大寫,做爲初學者仍是遵照得好。

 

(3)分析本身程序的bug

第5次做業:

全部的「正確請求測試多線程功能」樣例均有錯(公測未發現或是被發現bug)。

問題所在的類是Scheduler。

被發現了一個CRASH是因爲想向文件寫入結果,但文件已經關閉致使的。這暴露出我對於多線程同步控制還沒有掌握,且本身構造的測試樣例太寬鬆,很容易露出破綻。

從設計結構角度分析,我把全部的電梯調度方法全寫入一個調度器類。Scheduler類的代碼規模更是破了200行,遠遠超過其它類。

在總結課上,我才瞭解到有更加均衡的實現方式。總調度器只負責將請求分配給不一樣的電梯,而每部電梯對應一個專門的調度器負責排請求的執行前後順序。這種方式顯然更合適,既是遵循均衡原則,又符合實際的應用場景。

第6次做業:

對方沒有進行公測,且沒有發現bug,故不做分析。

第7次做業:

被發現了一個bug,爲新增節點「等待狀態下出租車的運行不具有隨機性」。

問題所在的類爲Taxi,方法爲run_edge

這個bug被髮如今情理之中,由於我曾經嘗試過實現出租車的隨機運行,可是失敗了(出租車發生了瞬移)。最終改爲了一版肯定性運行的方法。

(4)分析本身發現別人程序bug所採用的策略

不少學生(包括我)在編寫多線程程序時遇到的一個技術難點就是如何讓程序正常結束(在eclipse下是在控制檯上方看到<terminated>)。儘管這不是指導書的硬性要求,可是可以正常結束的程序勢必帶來更好的用戶體驗和更強的魯棒性。若是被測者沒有在readme中對程序的結束進行說明,或是說明能結束但實際上沒實現的,則能夠報告bug。

邊界條件是在編程過程當中須要着重考慮的。一些在實際狀況中徹底有可能出現,但編程者很難考慮到的測試點上每每容易發現bug。第7次做業我經過構造「乘客請求起始座標正好是出租車所在位置」的樣例,成功發現了別人的bug。

後期的做業不但注重程序正確性,並且對程序設計原則也提出了要求。測試者能夠閱讀被測代碼,發現其中不符合設計要求的部分,予以扣分。

 

(5)心得體會

1)線程安全

在線程安全方面,重點是把握課上重點講過的「生產者-消費者」模型,學會將共享對象的存取方法設置爲同步化的,以及方法內部具體的寫法。拿到指導書以後,在分析程序須要哪些對象、對象之間關係時,必須額外考慮哪些對象須要被共享的問題。不管是本身寫被共享類的代碼,仍是包裝爲線程安全類,都要想清楚哪些方法須要保證原子性,並使用synchronized關鍵字。

2)設計原則

從第7講開始,課後做業將程序設計原則也歸入了做業要求和互評範圍。設計原則與程序的正確性沒有直接的關係,而是爲了讓程序具備較好的可讀性、可擴展性。在軟件開發行業,用戶需求發生變動是常常遇到的事件。遵循課上講過的一些設計原則能夠加強程序的可擴展性。在需求變動時,只須要對原有程序進行有限的修改,而不是推倒重來。本身在3次電梯做業中,後面的做業每每不能有效利用前面做業的代碼,緣由在於本身沒有在一開始構造一個良好的設計,沒有遵循設計原則。另外一些原則是爲了程序可讀性,由於未來咱們開發的程序只是一個大項目的一部分。不但要保證別人放心調用,並且最好在代碼中清楚寫出本身的邏輯。可能通過後面幾回做業的訓練,我可以更深刻地理解設計原則。

相關文章
相關標籤/搜索