OO第二次博客做業

OO Unit2 總結

​ 第二單元的做業是面向多線程的電梯編程,經過這一單元的做業,筆者基本掌握了多線程編程的方法。算法

第五次做業

  • task:單部先來先服務調度電梯,用戶請求能夠在任意時刻到達。編程

  • 類圖

    時序圖

    設計策略安全

    雖然第一次做業僅僅只有一部電梯,可是須要一個專門的線程用於處理輸入,與電梯線程併發執行。因爲須要準備向多電梯擴展,我在此次做業設計時並無直接將輸入給到電梯,而是通過了scheduler中轉後,再由電梯得到而後執行。多線程

    此次做業我總共設計了兩個線程,InputHandler和Elevator,共享對象是Scheduler。InputHandler將處理好的請求放入Scheduler的隊列,ELevator將請求從Scheduler中取出而後執行。架構

    所以爲了保證線程安全,須要對Scheduler的requests隊列的操做作同步控制,具體體如今InputHandler向requests隊列放入請求和Elevator從requests隊列取請求時都須要先得到requests隊列的鎖。併發

    至於兩個線程之間的協同體如今1.requests隊列爲空時,電梯須要等待,我採用的是CPU輪詢的方法。2.InputHandler線程結束後,Elevator線程須要知曉,w爲此我在InputHandler中設置了一個hasInputFlag的變量,標誌是否還有輸出,電梯能夠經過查詢該標誌變量來檢查輸入線程是否結束,以便決定自身線程是否結束。框架

    優勢函數

    • 輸入處理和電梯模擬能夠併發執行,程序運行效率高。
    • 電梯的運行邏輯分離程度較高,每個小步驟都寫成了一個方法,而後用一些頂層方法包起來,主控制流只須要順序調用這些頂層方法就能夠了。

    缺點單元測試

    • CPU輪詢過於消耗CPU時間。
    • Scheduler並無單獨做爲一個線程,可擴展性不夠。
    • 電梯屬性硬編碼,可擴展性不夠。
  • OO度量分析 -- 類

    • LOC:類代碼行數。
    • OCavg:平均方法複雜度。
    • WMC:帶權方法複雜度。
    • NAAC:類屬性個數。
    • NOAC:類方法個數。
  • OO度量分析 -- 方法

    • CONTROL:控制語句數。
    • LOC:方法代碼行數。
    • ev(G):核心圈複雜度。
    • iv(G):方法設計複雜度。
    • v(G):圈複雜度。
  • 設計原則檢查

    • Single Responsibility Principle:每一個方法基本上都只負責一項功能的執行,符合單一職責原則。
    • Open Close Principle:因爲存在硬編碼等問題,可擴展性不高,對後續需求增長不利。
    • Liscov Substitution Principle:不存在子類的設計,知足里氏替換原則。
    • Interface Segregation Principle:不存在接口設計,知足接口分離原則。
    • Dependency Inversion Principle:沒有考慮將樓層也抽象爲對象,只是簡單進行了樓層數的記錄。

第六次做業

  • task:單部可捎帶電梯實現,用戶請求可隨時到達。測試

  • 類圖

    時序圖

    設計策略

    本次設計較第一次有了較大的改變。因爲調度器如今須要使用可捎帶算法來爲電梯分配請求,考慮到程序運行效率問題,調度器也能夠做爲一個單獨線程與InputHandler和Elevator線程併發執行。

    此次做業筆者總共設計了三個線程:InputHandler、Elevator和Scheduler。InputHandler與Scheduler的共享區包括requests隊列和inputOver標誌;Scheduler與Elevator的共享區包括requests隊列和runOver標誌。

    爲了保證線程安全,InputHandler對requests隊列的放入操做與Scheduler對requests隊列的取出操做都須要先申請鎖;Scheduler將請求放入電梯的requests隊列和電梯從本身的requests隊列中取請求都須要先申請鎖。

    本次做業線程間的協做體如今:首先由InputHandler接收輸入進行處理後放入Scheduler請求隊列;而後Scheduler執行調度算法,將請求分配給電梯;最後電梯執行運行算法,完成請求。爲了實現三個線程間的同步控制,每得到一個輸入後,InputHandler對Scheduler進行notify;當requests隊列爲空時,Scheduler處於wait狀態;Scheduler每分配一個請求後,對Elevator進行notify;Elevator的requests隊列爲空時,Elevator處於wait狀態。這樣既能夠保證不浪費CPU時間,又可以保證各個線程及時被喚醒工做。

    優勢

    • 對樓層進行了建模,提升了可擴展性。
    • 將電梯的運行參數包裝爲runPara、runState兩個屬性類,即防止了硬編碼提升了可擴展性,又不會讓電梯的邏輯顯得十分冗餘。
    • 不一樣類分工明確,相互之間只經過共享對象進行交互,耦合度很小。
    • 電梯設置了本身的請求隊列,便於向多電梯的狀況擴展。
    • 使用註冊的方式,使得調度器能夠知道電梯的信息。

    缺點

    • 電梯類的方法數過多,邏輯過於龐大。
  • OO度量分析 -- 類

    • LOC:類代碼行數。
    • OCavg:平均方法複雜度。
    • WMC:帶權方法複雜度。能夠看到電梯類的方法的權值很大,代表其方法的調用次數和頻率都很高。
    • NAAC:類屬性個數。
    • NOAC:類方法個數。
  • OO度量分析 -- 方法


    • CONTROL:控制語句數。
    • LOC:方法代碼行數。
    • ev(G):核心圈複雜度。
    • iv(G):方法設計複雜度。
    • v(G):圈複雜度。
  • 設計原則檢查

    • Single Responsibility Principle:每一個方法基本上都只負責一項功能的執行;InputHandler和Scheduler類的職責也較爲簡單,可是Elevator類的功能過於複雜。
    • Open Close Principle:電梯運行參數、樓層都實現了建模,可方便的擴展和修改;調度器分配框架搭建完善,若是有調度算法上的改變,只須要重寫調度函數便可。總的來講,符合開閉原則。
    • Liscov Substitution Principle:不存在子類的設計,知足里氏替換原則。
    • Interface Segregation Principle:不存在接口設計,知足接口分離原則。
    • Dependency Inversion Principle:電梯內部其實能夠進行進一步的抽象,好比將上行和下行的邏輯單獨分離爲一個運行器的類,這樣也能夠下降電梯類的複雜度。

第七次做業

  • task:三部運行參數不一樣的電梯,使用可捎帶調度算法,用戶請求實時到達。

  • 類圖

    時序圖

    設計策略

    本次做爲是多部電梯的運行,並且每部電梯的屬性有所不一樣。三部電梯之間是併發執行的。

    此次做業筆者總共設計了5個線程:InputHandler、Elevator和Scheduler。InputHandler與Scheduler的共享區包括requests隊列和inputOver標誌;Scheduler與Elevator的共享區包括每部電梯的requests隊列和runOver標誌。

    爲了保證線程安全,InputHandler對requests隊列的放入操做與Scheduler對requests隊列的取出操做都須要先申請鎖;Scheduler將請求放入電梯的requests隊列和電梯從本身的requests隊列中取請求都須要先申請鎖。

    本次做業線程間的協做體如今:首先由InputHandler接收輸入進行處理後放入Scheduler請求隊列;而後Scheduler執行調度算法,將請求分配給電梯;最後電梯執行運行算法,完成請求。爲了實現5個線程間的同步控制,每得到一個輸入後,InputHandler對Scheduler進行notify;當requests隊列爲空時,Scheduler處於wait狀態;Scheduler分配完當前隊列中全部請求後,對全部的Elevator進行notify;Elevator的requests隊列爲空時,Elevator處於wait狀態。

    此次做業還新增了換乘的功能,爲了實現換乘,筆者的策略是在Scheduler中就首先拆分好,第一段交由電梯執行,第二段暫存在Scheduler的transfer隊列中,當第一段被電梯執行完畢後,電梯通知調度器對第二段進行分配,這樣就保證了第一段的永遠先於第二段執行,實現了同步控制。而且因爲transfer隊列的存在,Scheduler線程結束的條件不只是輸入結束和requests隊列爲空,還要算上transfer對列也爲空才能結束線程,當全部請求分配完畢後,若transfer隊列不空,Scheduler會進入wait狀態,等待電梯通知。

    優勢

    • 架構清楚,各模塊功能界限清晰。
    • 進一步封裝了Floor類,設計了Floors類,而且封裝了Floor類的全部方法。
    • runState類提供瞭如up、down等方法,方便對電梯運行狀態進行設置。
    • 電梯與調度器的交互經過addToFloor和awakeTransfer這兩個方法完成,防止外部類直接對本類的屬性進行改變。
    • 電梯調度改用了掃描算法,運行效率提升。

    缺點

    • 電梯類的邏輯過於龐大。
  • OO度量分析 -- 類

    • LOC:類代碼行數。
    • OCavg:平均方法複雜度。調度器類中有分配算法的方法邏輯過大,所以致使平均方法複雜度提升。
    • WMC:帶權方法複雜度。電梯和調度器的方法的權重都很高。
    • NAAC:類屬性個數。電梯相對於第二次做業新增了一些屬性。
    • NOAC:類方法個數。
  • OO度量分析 -- 方法



    • CONTROL:控制語句數。每一個方法的控制語句數都較少。
    • LOC:方法代碼行數。
    • ev(G):核心圈複雜度。
    • iv(G):方法設計複雜度。
    • v(G):圈複雜度。調度器用於進行拆分請求的方法的複雜度略高。
  • 設計原則檢查

    • Single Responsibility Principle:Elevator類的職責功能過多。
    • Open Close Principle:在第二次做業的基礎上,新增了一些方法來知足新的需求;對電梯運行方法、調度器分配方法進行了修改,可是大致上是符合開閉原則的。
    • Liscov Substitution Principle:不存在子類的設計,知足里氏替換原則。
    • Interface Segregation Principle:不存在接口設計,知足接口分離原則。
    • Dependency Inversion Principle:電梯的抽象層次仍然不夠,upFloor和downFloor的邏輯能夠獨立爲類。

BUG分析

本身的BUG

​ 前三次做業在公測中都沒有出現bug,因爲未參加互測,所以沒有進一步發現bug。

測試的方法

  • 靜態檢查:在重要的邏輯部分對代碼作靜態檢查,好比調度器分配邏輯、電梯運行咯就。
  • 單元測試:在代碼編寫過程當中沒寫完一小部分獨立性較高的方法就對其進行單元測試,保證無誤後才進行以後的編寫。
  • 綜合測試:針對問題的規則,人爲製造必定的複雜樣例進行測試。對於換乘這種極容易出錯的地方,進行重點的測試。
  • 迴歸測試:三次做業,每一次做業的測試用例都向後兼容,記錄下前兩次的用例用於第三次做業,節省了部分時間。

心得體會

多線程編程最重要的一點就在於線程安全的處理,凡是涉及到了線程共享的部分都須要進行加鎖操做。這裏就須要咱們找到到底哪些地方出現了共享,一般共享出如今參數傳遞、返回值、引用變量賦值這些地方,對於多線程編程中的這些場景咱們必定要格外注意,對於出現了共享對象,要追蹤其全部使用位置,檢查操做是否安全,不然一旦出現不可控的安全問題,靠debug來查找問題來源是極爲困難的。

除了多線程編程外,這一單元筆者同時還接觸到了設計原則。SOLID五大經典原則能夠說是在實際開發過程當中應該隨時恪守的,從需求分析到架構設計到代碼實現,每一步都要注意設計原則,並且在實現完成後還要進行設計原則的檢查,在不當的地方進行重構以符合設計原則。不少同窗可能很討厭這種工做,認爲又麻煩有沒有意義,可是筆者認爲在實際的軟件開發過程當中,遵照設計原則是極其重要的。如今因爲做業規模小,並且迭代開發次數少,不遵循設計原則看起來影響不大,一旦到了社會上,軟件的開發每每規模龐大並且要通過不少次的迭代開發。在這種狀況下,若是沒有一個統一的設計規範,一我的一套規則,那相互之間的合做就會變得無比困難,別人開發的軟件你可能徹底無法讀懂,更別談進行迭代開發;即便你可以讀懂,若是該產品通過屢次迭代後,有些類的安全性、獨立性等都已經發生了改變,那麼要想在已有基礎上進行修改,就可能須要向後追溯到好久之前實現的代碼上去進行閱讀,白白浪費大量時間。

總的來講,設計原則應該貫穿於整個軟件開發的過程,遵照設計原則,能夠幫助咱們更好的進行設計和開發。

相關文章
相關標籤/搜索