面向對象第二單元總結——魔鬼電梯

寫在前面

OO課程已通過半,過去的第二單元主要是訓練了咱們的多線程設計,以電梯爲載體,步步深刻,層層遞進。本單元我學到了:java

  • 如何作一個線程安全的設計。
  • 如何去合理地使用Java的鎖機制。

下面我將以三次做業爲例,具體談一下個人收穫。python

第五次做業

此次做業的要求是寫一個傻瓜式調度的電梯,筆者也是按指導書去寫的,總體寫起來很輕鬆,也算入門了Java多線程的寫法、共享對象的使用以及鎖的使用。算法

代碼規模

圖片名稱

類圖

圖片名稱

UML

圖片名稱

第一次的業務邏輯很清晰,就是簡單的生產者-消費者模型,輸入類爲生產者,電梯類爲消費者,共享對象是調度器裏的請求隊列。能夠很簡單地實現傻瓜電梯的功能,也不容易出bug。安全

複雜度分析

Method ev(G) iv(G) v(G)
elevator.Elevator.Elevator(Scheduler) 1 1 1
elevator.Elevator.moveToFloor(int) 1 2 2
elevator.Elevator.personIn(int) 1 2 2
elevator.Elevator.personOut(int) 1 2 2
elevator.Elevator.run() 3 3 3
elevator.Main.main(String[]) 1 1 1
elevator.RequestIn.RequestIn(Scheduler) 1 1 1
elevator.RequestIn.run() 3 4 4
elevator.Scheduler.Scheduler() 1 1 1
elevator.Scheduler.addRequest(PersonRequest) 1 1 1
elevator.Scheduler.getQueue() 1 1 3
elevator.Scheduler.getRequest() 1 3 3
Class OCavg WMC
elevator.Elevator 1.4 7
elevator.Main 1 1
elevator.RequestIn 2 4
elevator.Scheduler 1.75 7

能夠看到第一次業務邏輯簡單,代碼的複雜度也相對小一點,只有電梯的運行方法稍顯複雜,這也是情理之中的。多線程

SOLID原則分析

本單元做業筆者未使用繼承和接口,因此如下只分析SRP和OCP。架構

單一責任原則(SRP)

筆者的設計符合SRP原則,輸入類只負責輸入,電梯只負責運行,調度器只負責存儲請求隊列。工具

開放封閉原則(OCP)

筆者在第一次做業中暫未考慮擴展性問題。性能

Bug分析

公測

筆者的程序在公測中未被發現bug。學習

互測

筆者的程序在互測中未被發現bug。測試

測試方法

隨機生成測試數據,用java程序按時間點向電梯輸入請求,獲得輸出後用python程序檢查最終的電梯狀態和人員狀態,看一下調度是否正確。

第六次做業

本次做業的要求是寫一個ALS調度算法的電梯,因爲此次做業加入了性能分評測,故筆者寫的電梯是Look調度算法。此次做業的邏輯稍顯複雜,怎麼去避免死鎖發生,怎麼去寫一個線程安全的架構是咱們考慮的重點。

代碼規模

圖片名稱

類圖

圖片名稱

UML

圖片名稱

第二次做業相比第一次做業,只增長了捎帶需求,而爲了適應多電梯的擴展,我對電梯系統作了重構,首先,增長Elevatorbuild類,負責生成多部電梯,而後Elevator按Look調度算法運行,每到一層樓都和Scheduler調度器進行一次交互,進行接送乘客。由於是單電梯,因此本次的調度器職責就是把收到的指令分配給電梯。

複雜度分析

Method ev(G) iv(G) v(G)
Main.main(String[]) 1 1 1
elevatorsystem.RequestInput.RequestInput(Scheduler) 1 1 1
elevatorsystem.RequestInput.run() 3 4 4
elevatorsystem.Scheduler.addRequest(PersonRequest) 1 1 1
elevatorsystem.Scheduler.getScheduler() 1 1 3
elevatorsystem.Scheduler.setRunning(Boolean) 1 1 1
elevatorsystem.elevator.Elevator.Elevator() 1 1 1
elevatorsystem.elevator.Elevator.check() 1 6 8
elevatorsystem.elevator.Elevator.close() 1 2 2
elevatorsystem.elevator.Elevator.doWait() 1 2 2
elevatorsystem.elevator.Elevator.elevatorStop() 1 6 11
elevatorsystem.elevator.Elevator.getArrival() 1 1 1
elevatorsystem.elevator.Elevator.getDirection() 1 1 1
elevatorsystem.elevator.Elevator.getFloor() 1 1 1
elevatorsystem.elevator.Elevator.getNextRequest() 1 4 4
elevatorsystem.elevator.Elevator.getRequestNum() 1 1 1
elevatorsystem.elevator.Elevator.getRunning() 1 1 1
elevatorsystem.elevator.Elevator.getStatus() 1 1 1
elevatorsystem.elevator.Elevator.isDown(PersonRequest) 1 1 1
elevatorsystem.elevator.Elevator.isUp(PersonRequest) 1 1 1
elevatorsystem.elevator.Elevator.load() 1 6 6
elevatorsystem.elevator.Elevator.lookDown() 4 2 4
elevatorsystem.elevator.Elevator.lookUp() 4 2 4
elevatorsystem.elevator.Elevator.moveDown() 1 2 3
elevatorsystem.elevator.Elevator.moveUp() 1 2 3
elevatorsystem.elevator.Elevator.open() 1 2 2
elevatorsystem.elevator.Elevator.run() 6 16 17
elevatorsystem.elevator.Elevator.setArrival(ArrayList ) 1 1 1
elevatorsystem.elevator.Elevator.setDirection(int) 1 1 1
elevatorsystem.elevator.Elevator.setFloor(int) 1 1 1
elevatorsystem.elevator.Elevator.setInf(int) 1 1 1
elevatorsystem.elevator.Elevator.setRequestNum(Integer) 1 1 1
elevatorsystem.elevator.Elevator.setRunning(Boolean) 1 1 1
elevatorsystem.elevator.Elevator.setStatus(Integer,ArrayList ) 1 1 1
elevatorsystem.elevator.Elevator.setSup(int) 1 1 1
elevatorsystem.elevator.Elevator.unload() 1 3 3
elevatorsystem.elevator.ElevatorBuild.InitOne() 3 2 3
elevatorsystem.elevator.ElevatorBuild.getElevatorBuild() 1 1 3
elevatorsystem.elevator.ElevatorBuild.getElevatorOne() 1 1 1
elevatorsystem.elevator.ElevatorBuild.run() 1 1 1
Class OCavg WMC
Main 1 1
elevatorsystem.RequestInput 2 4
elevatorsystem.Scheduler 1.67 5
elevatorsystem.elevator.Elevator 2.17 65
elevatorsystem.elevator.ElevatorBuild 2 8

不出所料,仍然是Elevator的運行方法和每層樓的接送乘客方法複雜度較高。

SOLID原則分析

單一責任原則(SRP)

筆者的設計符合SRP原則,輸入類只負責輸入,電梯的Builder類只負責生成電梯,電梯只負責運行已收到的請求,調度器只負責將收到的請求分給電梯。

開放封閉原則(OCP)

筆者在此次做業中充分考慮了向多電梯的可擴展性,新增ElevatorBuild類,負責根據不一樣參數生成不一樣種類的電梯,因此這個架構在第三次做業中得以沿用。

Bug分析

公測

筆者的程序在公測中未被發現bug。

互測

筆者的程序在互測中未被發現bug。筆者發現其餘同窗的一個bug,在某種狀況下,他的電梯會一直向上或向下運行而不會停下(所謂的飛天遁地),緣由應該是對邊界樓層和電梯轉向的處理不嚴密。

測試方法

筆者沿用了第一次做業的測試工具,定時投放+輸出數據正確性檢測。

第七次做業

最後一次做業增長了多電梯(3個),而且每一個電梯的可到達樓層不一樣,須要考慮換乘的狀況,總體難度較大,而且對線程穩定性的要求也很高。筆者的設計是採用三臺Look調度算法的電梯,每一個電梯只負責本身請求隊列裏的指令,須要換乘的指令會在指令輸入的時候被拆分紅兩條指令,在第一條指令執行完畢後將第二條指令加入請求隊列。

代碼規模

圖片名稱

類圖

圖片名稱

UML

圖片名稱

能夠看到,對於筆者的架構,從第二次做業到第三次做業,幾乎只須要修改調度器,其餘部分不作改動,因此筆者此次做業完成地也比較輕鬆。

複雜度分析

Method ev(G) iv(G) v(G)
Main.main(String[]) 1 1 1
elevatorsystem.RequestInput.RequestInput(Scheduler) 1 1 1
elevatorsystem.RequestInput.run() 3 4 4
elevatorsystem.Scheduler.InitChange(ArrayList<ArrayList >) 1 2 2
elevatorsystem.Scheduler.Scheduler() 1 1 1
elevatorsystem.Scheduler.addRequest(PersonRequest) 1 10 10
elevatorsystem.Scheduler.checkStatus(char,ArrayList ) 6 9 9
elevatorsystem.Scheduler.createMapA() 1 5 10
elevatorsystem.Scheduler.createMapB() 1 5 8
elevatorsystem.Scheduler.createMapC() 1 5 6
elevatorsystem.Scheduler.doWait(Object) 1 2 2
elevatorsystem.Scheduler.getChange() 1 1 1
elevatorsystem.Scheduler.getLock() 1 1 1
elevatorsystem.Scheduler.getMap(char) 3 1 3
elevatorsystem.Scheduler.getQueue(char) 3 1 3
elevatorsystem.Scheduler.getRequestNum(char) 3 1 3
elevatorsystem.Scheduler.getRunning() 1 1 1
elevatorsystem.Scheduler.getScheduler() 1 1 3
elevatorsystem.Scheduler.lock() 1 1 1
elevatorsystem.Scheduler.mapInit(HashMap<Integer, ArrayList >) 3 2 3
elevatorsystem.Scheduler.removeRequest(PersonRequest) 1 1 4
elevatorsystem.Scheduler.requestMapInit(HashMap<Integer, ArrayList >) 3 2 3
elevatorsystem.Scheduler.setRunning(Boolean) 1 1 1
elevatorsystem.Scheduler.takeApart(PersonRequest) 1 10 10
elevatorsystem.Scheduler.unLock() 1 1 1
elevatorsystem.elevator.Elevator.Elevator(Scheduler,Object) 1 1 1
elevatorsystem.elevator.Elevator.addAvailableFloor(int) 1 1 1
elevatorsystem.elevator.Elevator.check() 1 7 9
elevatorsystem.elevator.Elevator.close() 1 2 2
elevatorsystem.elevator.Elevator.doWait(Object) 1 2 2
elevatorsystem.elevator.Elevator.elevatorStop() 1 5 10
elevatorsystem.elevator.Elevator.getArrival() 1 1 1
elevatorsystem.elevator.Elevator.getDirection() 1 1 1
elevatorsystem.elevator.Elevator.getFloor() 1 1 1
elevatorsystem.elevator.Elevator.getNextRequest() 1 4 4
elevatorsystem.elevator.Elevator.isDown(PersonRequest) 1 1 1
elevatorsystem.elevator.Elevator.isUp(PersonRequest) 1 1 1
elevatorsystem.elevator.Elevator.load() 3 6 7
elevatorsystem.elevator.Elevator.lookDown() 4 2 4
elevatorsystem.elevator.Elevator.lookUp() 4 2 4
elevatorsystem.elevator.Elevator.moveDown() 1 2 3
elevatorsystem.elevator.Elevator.moveUp() 1 2 3
elevatorsystem.elevator.Elevator.open() 1 2 2
elevatorsystem.elevator.Elevator.run() 6 17 19
elevatorsystem.elevator.Elevator.setArrival(ArrayList ) 1 1 1
elevatorsystem.elevator.Elevator.setDirection(int) 1 1 1
elevatorsystem.elevator.Elevator.setFloor(int) 1 1 1
elevatorsystem.elevator.Elevator.setInf(int) 1 1 1
elevatorsystem.elevator.Elevator.setMaxContain(int) 1 1 1
elevatorsystem.elevator.Elevator.setMoveTime(int) 1 1 1
elevatorsystem.elevator.Elevator.setName(char) 1 1 1
elevatorsystem.elevator.Elevator.setOpenTime(int) 1 1 1
elevatorsystem.elevator.Elevator.setSup(int) 1 1 1
elevatorsystem.elevator.Elevator.unload() 1 7 8
elevatorsystem.elevator.ElevatorBuild.ElevatorBuild(Scheduler) 1 1 1
elevatorsystem.elevator.ElevatorBuild.InitA() 1 3 5
elevatorsystem.elevator.ElevatorBuild.InitB() 1 3 4
elevatorsystem.elevator.ElevatorBuild.InitC() 1 3 3
elevatorsystem.elevator.ElevatorBuild.getElevatorA() 1 1 1
elevatorsystem.elevator.ElevatorBuild.getElevatorB() 1 1 1
elevatorsystem.elevator.ElevatorBuild.getElevatorBuild(Scheduler) 1 1 3
elevatorsystem.elevator.ElevatorBuild.getElevatorC() 1 1 1
elevatorsystem.elevator.ElevatorBuild.run() 1 1 1
Class OCavg WMC
Main 1 1
elevatorsystem.RequestInput 2 4
elevatorsystem.Scheduler 3.14 69
elevatorsystem.elevator.Elevator 2.45 71
elevatorsystem.elevator.ElevatorBuild 1.89 17

能夠看到,調度器的添加請求方法和拆分請求方法,以及電梯的run方法複雜度很高。結合代碼不難看出複雜度高的緣由。調度器的添加請求方法須要作這麼幾件事:

  • 判斷電梯是否可直達,是否滿載,若是未滿載而且可直達則加入請求;
  • 若是所有滿載則選擇一部可直達的電梯加入請求;
  • 若是不可直達,則調用拆分請求方法進行指令拆分和添加。

這其中有很複雜的條件語句,因此方法複雜度略高。

至於電梯的run方法,是負責整個電梯運行邏輯的,因此複雜度略高也合乎情理。

SOLID原則分析

單一責任原則(SRP)

筆者的設計符合SRP原則,輸入類只負責輸入,電梯的Builder類只負責生成電梯,電梯只負責運行已收到的請求,調度器只負責接收和拆分請求,並分配給不一樣的電梯。

開放封閉原則(OCP)

筆者在此次做業中保留了對更多電梯的可擴展性,經過ElevatorBuild類可進行擴展。可是本次做業個人調度器是每一個電梯一個請求隊列,因此擴展起來比較麻煩,我想若是設計成全部電梯共用一個請求隊列的話,應該會更加便於擴展。

Bug分析

公測

本次公測筆者的程序炸了不少點,緣由是有一個條件語句加錯了位置,更改後可穩定經過所有測試點。

互測

筆者找到其餘同窗不少bug,有程序沒法結束的,有電梯超載的,有運行時間過長的,還有乘客未送到指定位置的。畢竟是C組,這麼多bug也就不足爲奇了。

總結

多線程設計讓我明白瞭如下幾點:

  • 必定要充分思考之後再動手寫代碼,否則在多線程設計中出了bug是很難調試的。代碼不規範,debug兩行淚。
  • 不要盲目地去使用鎖,synchronized當然好用,可是也不能濫用,要明確鎖的是哪一個對象,哪一個類。synchronized使用也是有技巧的,有時候一個方法裏面只須要鎖住一個對象就能夠,不必把整個方法都鎖起來,這樣會形成效率的下降。
  • 每寫好一個版本後,都須要對應充分的測試,一個優秀的工程設計師是兼顧正確性和高性能的,不要爲了追求一點點的性能而在設計上產生漏洞,更不要目測程序沒問題就不去作充分的測試。這是我在第三次做業中學到的,沒測試充分,致使bug沒被發現,因此炸掉了強測。

但願在之後的學習中,我能夠更好地掌握測試方法,寫出更加完美的程序。

相關文章
相關標籤/搜索