面向对象的程序设计-模块二课程总结
目錄
- 電梯作業的設計策略
- 基于度量的程序結構分析
- BUG分析及測試
- 心得體會
電梯作業的設計策略
在整體的架構上,我三次作業使用的設計策略較為統一,主要的組成部件有:
- 輸入控制線程:用于控制輸入,向主等待隊列中添加請求(生產者)
- 主控制線程:用于向電梯分發任務,從主等待隊列中拿請求(消費者)
- 主線程:主線程使用輪詢的方式查看任務是否全部執行完畢,并結束程序
- 電梯線程:用于運行每個電梯的等待隊列中的請求
- 主等待隊列WaitList:一個線程安全的共享對象,設置put和get方法來放入、拿走請求,并使用wait()和notifyAll()來阻塞或喚醒訪問該共享對象的線程
從具體的策略上講,使用了生產者&消費者模型,輸入控制線程和主控制線程構成一對生產者和消費者,二者的共享對象則是主等待隊列WaitList,這里我們加鎖來保證同一時間只能有一個線程訪問該共享對象,通過wait()和notify()來實現阻塞和喚醒訪問該共享對象的線程;
主控制線程向電梯線程分配其執行的人員,每一個電梯具有自己的等待隊列,而其任務就是循環執行分配到自己的等待隊列中的任務,主控制線程和電梯線程之間的共享對象就是每個電梯的等待人員隊列,這里我們同樣加鎖來保證同一時間只能有一個線程訪問等待人員隊列(共享對象);
- 在單部電梯執行任務的策略上,我使用了LOOK方法,即電梯選定一個方向運送乘客,在執行完當前方向上的所有任務后,再更換方向執行后續任務;
- 在人員分配策略上,我將能夠直達的請求按照一定的規則分配給對應電梯進行處理,在這里需要考慮的問題是各個電梯的負載均衡和最終的時間最優。為了將各個因素綜合考慮,在這里我設計了一種根據電梯和請求的當前狀態進行“打分”的分配方式,即根據電梯是否已滿、電梯是否正在執行任務、電梯目前所處樓層和方向和當前任務請求的匹配程度等幾個指標來為每個電梯打分,最終將待分配請求加入得分最高的電梯中(但是由于測試不夠&參數沒調,導致運行的效果并不好)。對于不能直達的請求,則會先執行前一部分(運到中轉層),由電梯線程放入大的等待隊列,再由主控制線程進行新一輪的分配。在中轉層的選擇上,我結合了請求的運行方向、分配電梯當前的運行方向和請求發出的樓層進行了分配。
- 程序結束的判定:輸入線程終止且電梯運行完畢。
在具體的判斷上,當輸入線程讀取到null時,將一個信號量isEnd置位,主線程通過輪詢+Sleep來判斷以下條件:- 信號量isEnd置位
- 主等待隊列為空
- 每個電梯處于空閑狀態且每個電梯的等待隊列、運行隊列均為空
在滿足上述的三個條件的情況下結束程序
但是,主線程可能在下述情況下出現錯誤的判定:- 最后一個任務從主等待隊列中取出,但還沒有交給電梯的時候
- 最后一個任務不能直達,從電梯中出來而未放入主等待隊列的時候
為了避免這樣的情況下程序的提前截止,我讓主線程在Sleep一小段時間后再次進行判斷,只有兩次判斷均能滿足的時候才會結束運行。
基于度量的程序結構分析
第五次作業:單部傻瓜電梯
- 復雜度分析:
本次作業中,Main由于需要監控各個線程的運行狀況并結束程序,且具有一定的邏輯判斷深度,所以造成了其OCavg指標復雜度較高;
而類Elevator由于需要維護其兩個隊列(運行隊列和等待隊列),并判斷和執行相應的任務,單類中執行的功能較多,方法間的互相調用過于復雜,導致其WMC指標復雜度過高。
- 類圖:
- 根據SOLID原則進行分析:
- SRP:電梯類Elevator需要執行的功能較多,類內方法互相調用復雜,沒有很好地滿足單一職責原則;
- OCP:由于電梯的調度策略改變,電梯和調度器均在后續進行了重寫
- 其他:本次作業中沒有繼承和接口,無抽象類
第六次作業:單部可捎帶電梯
- 復雜度分析:
在本次作業中,同樣是Elevator類設置的功能過多,導致其WMC復雜度較高,Main的邏輯判斷深度及復雜度較高?。 - 類圖:本次作業的類圖和第五次作業基本相同,不單獨列出
- 根據SOLID原則進行分析:
- SRP:同第五次作業,電梯類Elevator需要執行的任務過多;
- OCP:在本次作業中實現了單部電梯的LOOK算法,第七次多電梯作業中的不同屬性和捎帶策略的電梯是在繼承本次電梯的基礎上通過拓展實現的
- 其他:本次作業中沒有繼承和抽象類
第七次作業:多部智能電梯
- 復雜度分析:
- Elevator執行功能過于復雜,Main依然邏輯復雜度很高(太懶了?)
- Controller類需要監控各個電梯的運行狀態,并根據不同的情況決定其運行策略,導致其邏輯判斷的深度過高,在調試的過程中,這里也確實出現了很多BUG。
- 類圖:
UML時序圖分析:
三次作業的時序圖基本類似,挑這次作業的畫了一下- 根據SOLID原則進行分析:
- SRP:Elevator需要實現的功能過多,沒有很好地遵循單一職責原則;
- OCP:Elevator實現基本的LOOK+捎帶策略,ElevatorA/B/C通過繼承父類Elevator來修改其各自可以??康臉菍雍筒煌膶傩浴⑸訋Р呗?#xff1b;
- LSP:父類可以替換子類使用(但是調度策略不同);
- 其他:本次作業中沒有實現接口,無抽象類
BUG分析及測試
我的電梯在本階段作業的公測和互測中沒有出現BUG(也沒有性能?),一方面是由于本模塊的作業邏輯結構較為清晰,另一方面使用了一些極端樣例和大量隨機樣例進行了測試。對于同組同學的程序,我也沒有發現太多的問題。
在測試過程中,我使用了自動化測試來檢測正確性,也用它來繪制電梯運行期間的時空圖,以監測電梯的性能,統計了電梯的運行軌跡及負載(如下):
電梯運行時空圖 圖注:
藍色:A電梯
綠色:B電梯
紅色:C電梯
折線:電梯運行軌跡
每個方形的大小:當前電梯內人數
可以看出,在整個電梯運行的過程中,LOOK算法的執行情況較好。但是B電梯的負荷明顯過高,而C電梯的任務量太少(運行時間短、運送任務少),電梯整體的運行圖能夠更加直觀地展示在電梯生命周期內的運行負荷,也更易于找出任務分配的不均衡。
在互測階段,我也為我們組另一位同學畫出了這樣的運行軌跡圖,30S左右輸入的40條左右請求,他的電梯運行了160S以上:
從他的電梯運行圖中我們也能發現,他的單部電梯在執行任務的過程中使用的算法不是非常合理,例如B電梯出現了大量”折返跑“的情況;多電梯的任務分配也存在問題,C電梯在程序運行期間有長時間”摸魚“,A電梯亦有空等時間過長的情況。
心得體會
線程安全
- 在設計時考慮到線程之間的同步互斥關系
- 考慮不同線程和共享對象之間的關系
- 合理上鎖
- 考慮所有情況,避免不安全的情況出現
設計原則
- 首先保證線程安全
- 在設計時充分考慮以后出現的情況,OCP原則
- 設計清晰每個類的職責,遵循單一職責原則
- 降低類之間的耦合度
- 使用外部工具來進行正確性分析和性能評
轉載于:https://www.cnblogs.com/lebway/p/elevator.html
總結
以上是生活随笔為你收集整理的面向对象的程序设计-模块二课程总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 项目Alpha冲刺(团队)-代码规范、冲
- 下一篇: ASP.NET 应用程序遭遇Server