- OO第二单元总结
- 基于度量分析程序
- 第五次作业
- 类图分析及设计策略
- 时序图
- 代码复杂度分析
- 代码行数分析
- 第六次作业
- 类图分析及设计策略
- 时序图
- 代码复杂度分析
- 代码行数分析
- 第七次作业
- 类图分析及设计策略
- 时序图
- 代码复杂度分析
- 代码行数分析
- 第五次作业
- 多线程的协同及同步控制
- 用SOLID原则进行分析
- 分析bug
- 对比和心得体会
- 基于度量分析程序
OO第二单元总结
基于度量分析程序
第五次作业
类图分析及设计策略
在本次作业中采用生产者-消费者模型,共有七个类,在MainClass
中启动InputRequest
线程和Controller
线程,RequestList
作为共享对象,InputRequest
作为生产者添加新的Request
到RequestList
,Controller
作为消费者从RequestList
中获取Request
。同时,Controller
类中维护一个队列waitList
,适时添加新的Request
到RequestList
。
调度算法采取了Look算法,若新的Request
与电梯方向一致,并且上行时出发楼层比电梯现在楼层高,下行时出发楼层比现在楼层低,则可进入requestList
,否则进入等待队列waitList
。将电梯本次上行或下行所需到达楼层用floorSet
存储,调用floor()
方法或ceiling()
方法即可得到电梯下一个需要到达的楼层,到达楼层后Controller
发送指令给Elevator
,根据Elevator
内部的inElevatorList
上人或下人。当到达该方向最高或最低楼层后,变换方向,将waitList
中方向一致的Request
都加入requestList
,并抵达这次上行(下行)的最低(最高)楼层。大部分调度均由Controller
类完成。
没有输入时Controller await()
,改WorkState
为Waiting,有新的Request
时signalAll()
,改WorkState
为Running。当输入结束后,改WorkState
为Stop,Controller
检测到Stop并且ArrayList
均为空时,结束Controller
进程。
时序图
代码复杂度分析
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
unitwo.Controller.Controller(RequestList,Elevator) | 1 | 1 | 1 |
unitwo.Controller.addSubFloor() | 2 | 1 | 2 |
unitwo.Controller.addWaitList(Request) | 1 | 1 | 1 |
unitwo.Controller.awaitController() | 1 | 1 | 2 |
unitwo.Controller.changeDirection() | 1 | 5 | 7 |
unitwo.Controller.comeInElevator(int,Boolean) | 1 | 1 | 1 |
unitwo.Controller.comeOutElevator(int) | 1 | 1 | 1 |
unitwo.Controller.getNowFloor() | 1 | 1 | 1 |
unitwo.Controller.getWorkState() | 1 | 1 | 1 |
unitwo.Controller.isUpdown() | 1 | 1 | 1 |
unitwo.Controller.run() | 6 | 12 | 15 |
unitwo.Controller.setStop() | 1 | 1 | 1 |
unitwo.Controller.signalController() | 1 | 1 | 1 |
unitwo.Controller.subWaitList() | 2 | 3 | 4 |
unitwo.Elevator.Elevator() | 1 | 1 | 1 |
unitwo.Elevator.arriveFloor(int) | 1 | 1 | 1 |
unitwo.Elevator.closeDoor(int) | 1 | 1 | 1 |
unitwo.Elevator.comeOnElevator(ArrayList) | 1 | 1 | 1 |
unitwo.Elevator.comeOutElevator(int) | 1 | 3 | 3 |
unitwo.Elevator.getSize() | 1 | 1 | 1 |
unitwo.Elevator.openDoor(int) | 1 | 1 | 1 |
unitwo.InputRequest.InputRequest(RequestList,Controller) | 1 | 1 | 1 |
unitwo.InputRequest.run() | 3 | 7 | 7 |
unitwo.MainClass.main(String[]) | 1 | 1 | 1 |
unitwo.Request.Request(int,int,int) | 1 | 1 | 2 |
unitwo.Request.compareTo(Request) | 3 | 2 | 3 |
unitwo.Request.getInFloor() | 1 | 1 | 1 |
unitwo.Request.getOutFloor() | 1 | 1 | 1 |
unitwo.Request.inElevator() | 1 | 1 | 1 |
unitwo.Request.outElevator() | 1 | 1 | 1 |
unitwo.Request.whetherInElevator(int,Boolean) | 2 | 1 | 3 |
unitwo.Request.whetherInSet(int,Boolean) | 3 | 1 | 7 |
unitwo.Request.whetherInSetFW(int,Boolean) | 3 | 1 | 5 |
unitwo.Request.whetherOutElevator(int) | 2 | 1 | 2 |
unitwo.RequestList.RequestList(ArrayList) | 1 | 1 | 1 |
unitwo.RequestList.cleanSet() | 1 | 3 | 3 |
unitwo.RequestList.get(int,boolean) | 1 | 3 | 3 |
unitwo.RequestList.getMaxMinFloor(Boolean) | 3 | 3 | 3 |
unitwo.RequestList.getNextFloor(int,Boolean) | 4 | 4 | 4 |
unitwo.RequestList.getSize() | 1 | 1 | 1 |
unitwo.RequestList.put(Request) | 1 | 1 | 1 |
从上表可以看出,由于将许多调度都设计在了Controller
进程的run()
方法中,导致该方法复杂度较高,不利于后续作业扩展,同时在一些判断是否上电梯,是否进入requestList
的方法中,判断语句较多,导致圈复杂度较高。
代码行数分析
Package Name | Type Name | Method Name | LOC | CC | PC |
---|---|---|---|---|---|
unitwo | Controller | Controller | 8 | 1 | 2 |
unitwo | Controller | addWaitList | 3 | 1 | 1 |
unitwo | Controller | subWaitList | 14 | 4 | 0 |
unitwo | Controller | getNowFloor | 3 | 1 | 0 |
unitwo | Controller | isUpdown | 3 | 1 | 0 |
unitwo | Controller | addSubFloor | 8 | 2 | 0 |
unitwo | Controller | run | 54 | 8 | 0 |
unitwo | Controller | setStop | 3 | 1 | 0 |
unitwo | Controller | getWorkState | 3 | 1 | 0 |
unitwo | Controller | awaitController | 13 | 1 | 0 |
unitwo | Controller | signalController | 10 | 1 | 0 |
unitwo | Controller | changeDirection | 28 | 4 | 0 |
unitwo | Controller | comeInElevator | 5 | 1 | 2 |
unitwo | Controller | comeOutElevator | 3 | 1 | 1 |
unitwo | Elevator | Elevator | 3 | 1 | 0 |
unitwo | Elevator | openDoor | 3 | 1 | 1 |
unitwo | Elevator | closeDoor | 3 | 1 | 1 |
unitwo | Elevator | arriveFloor | 3 | 1 | 1 |
unitwo | Elevator | comeOnElevator | 3 | 1 | 1 |
unitwo | Elevator | comeOutElevator | 9 | 3 | 1 |
unitwo | Elevator | getSize | 3 | 1 | 0 |
unitwo | InputRequest | InputRequest | 4 | 1 | 2 |
unitwo | InputRequest | run | 32 | 7 | 0 |
unitwo | MainClass | main | 11 | 1 | 1 |
unitwo | Request | Request | 11 | 2 | 3 |
unitwo | Request | getInFloor | 3 | 1 | 0 |
unitwo | Request | getOutFloor | 3 | 1 | 0 |
unitwo | Request | compareTo | 11 | 3 | 1 |
unitwo | Request | whetherOutElevator | 8 | 2 | 1 |
unitwo | Request | whetherInElevator | 8 | 2 | 2 |
unitwo | Request | whetherInSet | 11 | 3 | 2 |
unitwo | Request | whetherInSetFW | 11 | 3 | 2 |
unitwo | Request | outElevator | 3 | 1 | 0 |
unitwo | Request | inElevator | 3 | 1 | 0 |
unitwo | RequestList | RequestList | 4 | 1 | 1 |
unitwo | RequestList | put | 5 | 1 | 1 |
unitwo | RequestList | get | 12 | 3 | 2 |
unitwo | RequestList | getNextFloor | 20 | 4 | 2 |
unitwo | RequestList | cleanSet | 10 | 3 | 0 |
unitwo | RequestList | getMaxMinFloor | 11 | 3 | 1 |
unitwo | RequestList | getSize | 3 | 1 | 0 |
从代码行数中也可以看出来两个进程的run()
方法行数较多,复杂度高,不利于后续作业的扩展。
第六次作业
第六次作业主要从单部电梯改为了多部电梯,增加了地下层并且为电梯增加了人数上限。
类图分析及设计策略
在本次作业中采取Work Thread模式,共七个类。InputRequest
类为委托者(Client),Controller
类作为通道(Channel),Elevator
类作为工人(Worker),Request
类即为请求。Controller
类作为共享对象,同时承担了大部分的调度责任,为每个Elevator
分配合适的Request
,并且数量不超过上限,Elevator
只负责完成分配给他的请求。每个Elevator
都实例化一个WaitList
,管理分配给该电梯的乘客,进行电梯内部乘客进电梯和出电梯的调度。本次作业中还是只有InputRequest
线程和Elevator
线程。
这次作业还是采取Look算法,因为大部分设计沿用了上次作业。如电梯改变方向、需到达楼层的计算等。但因为改为多部电梯,所以在Controller
的调度,putRequest()
方法中,若Request
上(下)行,则在方向一致、未超载且现在楼层低(高)于上电梯的楼层的电梯中选择人数最少的一部电梯,添加入该部电梯所属的WaitList
中维护的容器中,否则添加入Controller
中的容器,等待下次分配。在这种调度算法下,分配给电梯的请求不会超过上限,并且能在一次上行或下行中全部完成。而Elevator
除了与上次作业相同,会在电梯换方向时从Controller
的未分配乘客中找到方向一致的Request
分配给自己,还会在从满载到有人下电梯的时刻,从Controller
的未分配中找到不超数量的合适的Request
加入。
当电梯完成所有分配给自己的请求并且Controller
中没有未分配请求时await()
,改WorkState
为Waiting,有新的Request
时signalAll()
,改WorkState
为Running。当输入结束后,改WorkState
为Stop,Elevator
检测到Stop并且完成所有分配给自己的请求,Controller
中也没有未分配请求时,结束Elevator
进程。
时序图
代码复杂度分析
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
unitwo.Controller.Controller(int) | 1 | 1 | 2 |
unitwo.Controller.awaitElevator(int) | 1 | 1 | 2 |
unitwo.Controller.getRequest(int,int,int,Boolean) | 8 | 10 | 12 |
unitwo.Controller.getRequsetChange(boolean,int,int) | 8 | 8 | 10 |
unitwo.Controller.getSize() | 1 | 1 | 1 |
unitwo.Controller.putRequest(Request) | 4 | 7 | 10 |
unitwo.Controller.setStop() | 1 | 2 | 2 |
unitwo.Controller.signalElevator() | 1 | 2 | 2 |
unitwo.Controller.startWork() | 1 | 2 | 2 |
unitwo.Elevator.Elevator(char,Controller) | 1 | 1 | 1 |
unitwo.Elevator.addRequest(Request) | 1 | 1 | 1 |
unitwo.Elevator.addSubFloor() | 2 | 1 | 2 |
unitwo.Elevator.arriveDestination() | 1 | 3 | 3 |
unitwo.Elevator.arriveFloor(int) | 1 | 1 | 2 |
unitwo.Elevator.changeDirection() | 1 | 1 | 1 |
unitwo.Elevator.changeElevatorDirection() | 1 | 5 | 7 |
unitwo.Elevator.changeUpdown() | 1 | 1 | 1 |
unitwo.Elevator.closeDoor(int) | 1 | 1 | 2 |
unitwo.Elevator.getElevatorState() | 1 | 1 | 1 |
unitwo.Elevator.isUpdown() | 1 | 1 | 1 |
unitwo.Elevator.openDoor(int) | 1 | 1 | 2 |
unitwo.Elevator.run() | 6 | 11 | 13 |
unitwo.Elevator.setElevatorState(ElevatorState) | 1 | 1 | 1 |
unitwo.Elevator.whetherInSetBegin(Request) | 1 | 8 | 9 |
unitwo.InputRequest.run() | 3 | 4 | 6 |
unitwo.MainClass.main(String[]) | 1 | 1 | 1 |
unitwo.Request.Request(int,int,int) | 1 | 1 | 2 |
unitwo.Request.compareTo(Request) | 4 | 1 | 4 |
unitwo.Request.equals(Object) | 3 | 2 | 4 |
unitwo.Request.getId() | 1 | 1 | 1 |
unitwo.Request.getInFloor() | 1 | 1 | 1 |
unitwo.Request.getOutFloor() | 1 | 1 | 1 |
unitwo.Request.hashCode() | 1 | 1 | 1 |
unitwo.Request.inElevator(char) | 1 | 1 | 2 |
unitwo.Request.isUpdown() | 1 | 1 | 1 |
unitwo.Request.outElevator(char) | 1 | 1 | 2 |
unitwo.Request.whetherInElevator(int,Boolean) | 2 | 1 | 3 |
unitwo.Request.whetherOutElevator(int) | 2 | 1 | 2 |
unitwo.WaitList.WaitList() | 1 | 1 | 1 |
unitwo.WaitList.addRequest(Request,char) | 1 | 1 | 1 |
unitwo.WaitList.cleanSet() | 1 | 5 | 5 |
unitwo.WaitList.comInElevator(int,boolean,char) | 1 | 3 | 3 |
unitwo.WaitList.comeOutElevator(int,char) | 1 | 3 | 3 |
unitwo.WaitList.getCustomer() | 1 | 1 | 1 |
unitwo.WaitList.getMaxMinFloor(Boolean) | 3 | 3 | 3 |
unitwo.WaitList.getNextFloor(int,Boolean) | 4 | 4 | 4 |
上次作业进程的run()
方法复杂度较高,本次作业中将Elevator
的run()
方法拆分出一部分,与上次相比,复杂度有所降低,但因为一些关于是否await()
和是否结束进程的判断都在run()
方法中,所以复杂度还是较高。并且在调度器分配Request
的几个方法中因为涉及到许多电梯状态以及Request
成员变量的判断导致复杂度也较高。
代码行数分析
Package Name | Type Name | Method Name | LOC | CC | PC |
---|---|---|---|---|---|
unitwo | Controller | Controller | 12 | 2 | 1 |
unitwo | Controller | startWork | 5 | 2 | 0 |
unitwo | Controller | putRequest | 37 | 9 | 1 |
unitwo | Controller | getRequest | 43 | 10 | 4 |
unitwo | Controller | awaitElevator | 13 | 1 | 1 |
unitwo | Controller | signalElevator | 12 | 2 | 0 |
unitwo | Controller | getRequsetChange | 43 | 10 | 3 |
unitwo | Controller | getSize | 3 | 1 | 0 |
unitwo | Controller | setStop | 6 | 2 | 0 |
unitwo | Elevator | Elevator | 11 | 1 | 2 |
unitwo | Elevator | addRequest | 4 | 1 | 1 |
unitwo | Elevator | run | 44 | 7 | 0 |
unitwo | Elevator | changeUpdown | 3 | 1 | 0 |
unitwo | Elevator | arriveDestination | 22 | 3 | 0 |
unitwo | Elevator | whetherInSetBegin | 19 | 5 | 1 |
unitwo | Elevator | openDoor | 7 | 2 | 1 |
unitwo | Elevator | closeDoor | 7 | 2 | 1 |
unitwo | Elevator | arriveFloor | 7 | 2 | 1 |
unitwo | Elevator | addSubFloor | 8 | 2 | 0 |
unitwo | Elevator | changeDirection | 7 | 1 | 0 |
unitwo | Elevator | changeElevatorDirection | 26 | 4 | 0 |
unitwo | Elevator | setElevatorState | 3 | 1 | 1 |
unitwo | Elevator | getElevatorState | 3 | 1 | 0 |
unitwo | Elevator | isUpdown | 3 | 1 | 0 |
unitwo | InputRequest | run | 32 | 5 | 0 |
unitwo | MainClass | main | 5 | 1 | 1 |
unitwo | Request | Request | 11 | 2 | 3 |
unitwo | Request | getId | 3 | 1 | 0 |
unitwo | Request | getInFloor | 3 | 1 | 0 |
unitwo | Request | getOutFloor | 3 | 1 | 0 |
unitwo | Request | isUpdown | 3 | 1 | 0 |
unitwo | Request | equals | 10 | 3 | 1 |
unitwo | Request | hashCode | 3 | 1 | 0 |
unitwo | Request | compareTo | 14 | 4 | 1 |
unitwo | Request | whetherOutElevator | 8 | 2 | 1 |
unitwo | Request | whetherInElevator | 8 | 2 | 2 |
unitwo | Request | outElevator | 7 | 2 | 1 |
unitwo | Request | inElevator | 7 | 2 | 1 |
unitwo | WaitList | WaitList | 5 | 1 | 0 |
unitwo | WaitList | addRequest | 11 | 1 | 2 |
unitwo | WaitList | getNextFloor | 26 | 4 | 2 |
unitwo | WaitList | cleanSet | 17 | 5 | 0 |
unitwo | WaitList | getMaxMinFloor | 17 | 3 | 1 |
unitwo | WaitList | comInElevator | 10 | 3 | 3 |
unitwo | WaitList | comeOutElevator | 9 | 3 | 2 |
unitwo | WaitList | getCustomer | 9 | 1 | 0 |
从行数中也可看出,行数较多的也是复杂度较高的几个方法,如上述提到的Elevator
的run()
方法和Controller
中负责分配Request
的几个方法。
第七次作业
在本次作业中,将电梯分为三类,每类具有不同的停靠楼层、运行时间、载客量,并且可以动态增加各种类型的电梯。
类图分析及设计策略
本次作业中有八个类,多数架构与上次作业相同,采取Work Thread模式。此外,Controller
负责总调度,保证分配给每个电梯的Request
是合适的(在一次上行或下行中可全部完成)且不超上限。Elevator
仅需完成分配给自己的Request
,每个Elevator
拥有的ViceController
负责管理分配给电梯的Request
。
本次作业大体上依然是Look算法,只是增加了关于停靠楼层的调度,改变了一些判断条件。若Request
可直达则不换乘,若需要换乘则在一开始便决定好换乘楼层,修改Request
的outFloor
为换乘楼层,新增一个Request
加入Controller
新增的用于存储新产生Request
的 ArrayList
,即secondTravel
中,当该Request
完成后,从Controller
中找到换乘新生成的Request
,重新putRequest()
。并且需换乘的Request
会为第二次乘电梯所用的电梯设置一个TargetFloor
,即为第二次乘电梯的上电梯楼层,若该电梯无分配的Request
,则会抵达TargetFloor
之后再await()
,在Request
频率低的时候,可节约换乘时间。同时,在调度的时候修改了判断条件,增加了是否可到达的条件。
为动态增加电梯的需求在Controller
类中增加了addElevator()
方法,在电梯创建时即设置好载客量、运行时间等。同时修改了电梯线程结束的条件,其余设计几乎不变。
时序图
代码复杂度分析
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
unitwo.Controller.Controller() | 1 | 1 | 1 |
unitwo.Controller.addElevator(String,String) | 1 | 2 | 3 |
unitwo.Controller.awaitElevator(int) | 1 | 2 | 3 |
unitwo.Controller.getRequest(int,int,int,Boolean) | 8 | 8 | 10 |
unitwo.Controller.getRequsetChange(boolean,int,int) | 8 | 8 | 10 |
unitwo.Controller.getSize() | 1 | 1 | 1 |
unitwo.Controller.getTransferFloor(Request) | 1 | 7 | 11 |
unitwo.Controller.needTransfer(Request) | 1 | 3 | 3 |
unitwo.Controller.putRequest(Request) | 1 | 2 | 2 |
unitwo.Controller.secondPutRequest(Request) | 3 | 3 | 3 |
unitwo.Controller.setStop() | 1 | 2 | 2 |
unitwo.Controller.setTarget(Request) | 4 | 4 | 4 |
unitwo.Controller.signalElevator() | 1 | 3 | 3 |
unitwo.Controller.startWork() | 1 | 2 | 2 |
unitwo.Controller.throughRequest(Request) | 4 | 8 | 11 |
unitwo.Elevator.Elevator(String,Controller,int[],int,int,int) | 1 | 1 | 1 |
unitwo.Elevator.addRequest(Request) | 1 | 1 | 1 |
unitwo.Elevator.addSubFloor() | 2 | 1 | 2 |
unitwo.Elevator.arriveDestination() | 1 | 3 | 3 |
unitwo.Elevator.arriveFloor(int) | 1 | 1 | 2 |
unitwo.Elevator.changeDirection() | 1 | 1 | 1 |
unitwo.Elevator.changeElevatorDirection() | 1 | 5 | 7 |
unitwo.Elevator.changeUpdown() | 1 | 1 | 1 |
unitwo.Elevator.closeDoor(int) | 1 | 1 | 2 |
unitwo.Elevator.getElevatorState() | 1 | 1 | 1 |
unitwo.Elevator.isUpdown() | 1 | 1 | 1 |
unitwo.Elevator.openDoor(int) | 1 | 1 | 2 |
unitwo.Elevator.run() | 7 | 11 | 14 |
unitwo.Elevator.setElevatorState(ElevatorState) | 1 | 1 | 1 |
unitwo.Elevator.setTargetFloor(int) | 1 | 1 | 1 |
unitwo.Elevator.toTargetFloor() | 4 | 4 | 7 |
unitwo.Elevator.whetherAvailable(Request) | 2 | 1 | 3 |
unitwo.Elevator.whetherGetRequest(Request) | 3 | 10 | 11 |
unitwo.Elevator.whetherGetRequestChange(Request) | 2 | 3 | 4 |
unitwo.Elevator.whetherInSetBegin(Request) | 1 | 10 | 11 |
unitwo.InputRequest.run() | 3 | 6 | 8 |
unitwo.MainClass.main(String[]) | 1 | 1 | 1 |
unitwo.Request.Request(int,int,int,boolean,boolean) | 1 | 1 | 2 |
unitwo.Request.getFinalFloor() | 1 | 1 | 1 |
unitwo.Request.getId() | 1 | 1 | 1 |
unitwo.Request.getInFloor() | 1 | 1 | 1 |
unitwo.Request.getOutFloor() | 1 | 1 | 1 |
unitwo.Request.inElevator(String) | 1 | 1 | 2 |
unitwo.Request.isFirstTravel() | 1 | 1 | 1 |
unitwo.Request.isReady() | 1 | 1 | 1 |
unitwo.Request.isTransfer() | 1 | 1 | 1 |
unitwo.Request.isUpdown() | 1 | 1 | 1 |
unitwo.Request.outElevator(String) | 1 | 1 | 2 |
unitwo.Request.setFinalFloor(int) | 1 | 1 | 1 |
unitwo.Request.setOutFloor(int) | 1 | 1 | 2 |
unitwo.Request.setReady(boolean) | 1 | 1 | 1 |
unitwo.Request.setTransfer(boolean) | 1 | 1 | 1 |
unitwo.Request.whetherInElevator(int,Boolean) | 2 | 1 | 3 |
unitwo.Request.whetherOutElevator(int) | 2 | 1 | 2 |
unitwo.SafeOutPut.println(String) | 1 | 1 | 1 |
unitwo.ViceController.ViceController(Controller) | 1 | 1 | 1 |
unitwo.ViceController.addRequest(Request) | 1 | 1 | 1 |
unitwo.ViceController.cleanSet() | 1 | 5 | 5 |
unitwo.ViceController.comInElevator(int,boolean,String) | 1 | 5 | 5 |
unitwo.ViceController.comeOutElevator(int,String) | 1 | 5 | 5 |
unitwo.ViceController.getCustomer() | 1 | 1 | 1 |
unitwo.ViceController.getMaxMinFloor(Boolean) | 3 | 3 | 3 |
unitwo.ViceController.getNextFloor(int,Boolean) | 4 | 4 | 4 |
与上次作业有些类似,复杂度较高的方法是Controller
为电梯分配Request
的几个方法和在这几个方法中调用的判断该Request
是否分配给该电梯的方法。这些方法都具有复杂的判断条件,导致最后复杂度较高、耦合度也较高,不利于扩展,可重用性、可移植性都较差。
代码行数分析
mine | unitwo | Controller | Controller | 13 | 1 | 0 |
---|---|---|---|---|---|---|
mine | unitwo | Controller | startWork | 5 | 2 | 0 |
mine | unitwo | Controller | addElevator | 13 | 3 | 2 |
mine | unitwo | Controller | needTransfer | 7 | 3 | 1 |
mine | unitwo | Controller | throughRequest | 37 | 9 | 1 |
mine | unitwo | Controller | getTransferFloor | 37 | 9 | 1 |
mine | unitwo | Controller | setTarget | 12 | 4 | 1 |
mine | unitwo | Controller | secondPutRequest | 11 | 3 | 1 |
mine | unitwo | Controller | putRequest | 10 | 2 | 1 |
mine | unitwo | Controller | getRequest | 43 | 10 | 4 |
mine | unitwo | Controller | awaitElevator | 15 | 2 | 1 |
mine | unitwo | Controller | signalElevator | 14 | 3 | 0 |
mine | unitwo | Controller | getRequsetChange | 43 | 10 | 3 |
mine | unitwo | Controller | getSize | 3 | 1 | 0 |
mine | unitwo | Controller | setStop | 12 | 2 | 0 |
mine | unitwo | Elevator | Elevator | 14 | 1 | 6 |
mine | unitwo | Elevator | addRequest | 4 | 1 | 1 |
mine | unitwo | Elevator | run | 52 | 10 | 0 |
mine | unitwo | Elevator | whetherAvailable | 10 | 2 | 1 |
mine | unitwo | Elevator | changeUpdown | 3 | 1 | 0 |
mine | unitwo | Elevator | toTargetFloor | 33 | 5 | 0 |
mine | unitwo | Elevator | arriveDestination | 22 | 3 | 0 |
mine | unitwo | Elevator | whetherInSetBegin | 22 | 6 | 1 |
mine | unitwo | Elevator | whetherGetRequest | 11 | 3 | 1 |
mine | unitwo | Elevator | whetherGetRequestChange | 8 | 2 | 1 |
mine | unitwo | Elevator | openDoor | 7 | 2 | 1 |
mine | unitwo | Elevator | closeDoor | 7 | 2 | 1 |
mine | unitwo | Elevator | arriveFloor | 7 | 2 | 1 |
mine | unitwo | Elevator | addSubFloor | 8 | 2 | 0 |
mine | unitwo | Elevator | changeDirection | 7 | 1 | 0 |
mine | unitwo | Elevator | changeElevatorDirection | 26 | 4 | 0 |
mine | unitwo | Elevator | setElevatorState | 3 | 1 | 1 |
mine | unitwo | Elevator | setTargetFloor | 3 | 1 | 1 |
mine | unitwo | Elevator | getElevatorState | 3 | 1 | 0 |
mine | unitwo | Elevator | isUpdown | 3 | 1 | 0 |
mine | unitwo | InputRequest | run | 38 | 7 | 0 |
mine | unitwo | MainClass | main | 5 | 1 | 1 |
mine | unitwo | Request | Request | 15 | 2 | 5 |
mine | unitwo | Request | setOutFloor | 9 | 2 | 1 |
mine | unitwo | Request | getFinalFloor | 3 | 1 | 0 |
mine | unitwo | Request | setFinalFloor | 3 | 1 | 1 |
mine | unitwo | Request | isReady | 3 | 1 | 0 |
mine | unitwo | Request | setReady | 3 | 1 | 1 |
mine | unitwo | Request | getId | 3 | 1 | 0 |
mine | unitwo | Request | setTransfer | 3 | 1 | 1 |
mine | unitwo | Request | isFirstTravel | 3 | 1 | 0 |
mine | unitwo | Request | isTransfer | 3 | 1 | 0 |
mine | unitwo | Request | getInFloor | 3 | 1 | 0 |
mine | unitwo | Request | getOutFloor | 3 | 1 | 0 |
mine | unitwo | Request | isUpdown | 3 | 1 | 0 |
mine | unitwo | Request | whetherOutElevator | 8 | 2 | 1 |
mine | unitwo | Request | whetherInElevator | 8 | 2 | 2 |
mine | unitwo | Request | outElevator | 7 | 2 | 1 |
mine | unitwo | Request | inElevator | 7 | 2 | 1 |
mine | unitwo | SafeOutPut | println | 3 | 1 | 1 |
mine | unitwo | ViceController | ViceController | 6 | 1 | 1 |
mine | unitwo | ViceController | addRequest | 11 | 1 | 1 |
mine | unitwo | ViceController | getNextFloor | 26 | 4 | 2 |
mine | unitwo | ViceController | cleanSet | 17 | 5 | 0 |
mine | unitwo | ViceController | getMaxMinFloor | 17 | 3 | 1 |
mine | unitwo | ViceController | comInElevator | 14 | 4 | 3 |
mine | unitwo | ViceController | comeOutElevator | 13 | 4 | 2 |
mine | unitwo | ViceController | getCustomer | 9 | 1 | 0 |
从代码行数、每个方法的规模上也可看出上述复杂度分析中遇到的问题。行数较多的类也是复杂度较高的类,集中在分配Request
的几个方法和电梯本身上行下行调度的方法。
多线程的协同及同步控制
在三次作业中采取了较简单的线程设计,仅有电梯线程和输入线程两种。第一次作业中采取生产者-消费者模式,以RequestList
为共享对象,后两次作业中采取Work Thread模式,以Controller
为共享对象。
主要在三种地方需要加锁。第一个是共享对象Controller
中putRequest()
和getRequest()
等需要判断电梯状态再调用的方法和改变电梯状态方法的同步互斥,第二个是维护电梯内部存储Request
的容器和需要通过该容器得到电梯下一个停靠楼层等信息的方法的读写互斥,采用了读写锁提高效率,第三个是关于电梯的await()
、signnal()
方法的锁。
因为后两种锁内没有其他引用,所以即使第一种锁会嵌套后两种,也不会有循环引用导致的死锁。但关于第一类锁,因为在Elevator
线程中需要判断的地方较多,即check-then-act较多,而且往往check
在Elevator
中,act
调用Controller
方法,所以有一些锁加在了调用Controller
方法的Elevator
代码的内部,而难以通过将Controller
设计为线程安全类来实现线程安全,虽然能实现线程安全的目标,但代码的可移植性、可重用性较差,同时也增大了加锁的区域,降低了效率。
用SOLID原则进行分析
-
SRP原则
每个类或方法都只有一个明确的职责。
作业中采取Work Thread模式。
InputRequest
类为委托者(Client),Controller
类作为通道(Channel),Elevator
类作为工人(Worker),Request
类即为请求。Controller
类作为共享对象,同时承担了调度的责任,为每个Elevator
分配合适的Request
,并且数量不超过上限,Elevator
只负责完成分配给他的请求。每个Elevator
都实例化的ViceController
,管理分配给该电梯的乘客,进行电梯内部乘客进电梯和出电梯的调度。多数方法和类都拥有明确的职责。 -
OCP原则
无需修改已有实现(close),而是通过扩展来增加新功能(open)。
三次作业中都采用Look算法,第一次使用生产者-消费者模式,后两次采取Work Thread模式。代码变动不多,仅在迭代的过程中增加了一些关于分配到哪个电梯以及换乘策略的调度,修改了一些关于电梯等待或是停止的判断条件。虽然针对这三次作业来说代码变动很少,但都需要修改已有代码,而且没有使用继承和接口,扩展性还是较差。
-
LSP 原则
任何父类出现的地方都可以使用子类来代替,并不会导致使用相应类的程序出现错误。
在本次作业中无继承。
-
ISP原则
一个接口封装一组高度内聚的操作。
在本次作业中未使用接口,使代码的灵活性和扩展性都较差,不符合这一原则。
-
DIP原则
依赖倒置原则。
因为没有使用接口,所以这一原则的完成度也较差。
分析bug
- 新建一个类,随机生成测试数据,将生成数据直接输入到程序中。通过改变生成输入时间的范围和楼层的范围进行不同的测试。检查结果是否有死锁、超时或者WA。
- 调试时,新建一个Print类,在其它类中调用Print类的静态方法,输出关键信息,同时以断点调试和JProfiler辅助。
- 在三次强测和互测中均未发现bug。
- 在互测时主要通过测试判断是否有死锁、超时等来发现bug。
对比和心得体会
在本单元作业中,我学习到了许多多线程方面的知识,如:线程安全、多线程设计模式等,学会了应用生产者-消费者模式和Work Thread模式,掌握了电梯调度的Look算法,然后在Look算法的基础上扩展,也取得了较好的性能分。但还存在一些问题:
-
虽然在三次作业,代码的修改量不大,但没有使用继承和接口,使代码的扩展性较差。
-
为了应对check-then-act,部分锁加在了代码内部,很难通过设计线程安全的共享对象类来解决一些线程安全问题。
-
线程的
run()
方法不够简洁,承担了很多功能。 -
主调度器
Controller
承担了较多功能。 -
有许多复杂的判断语句,导致代码的复用性较低、复杂度较高。
-
在部分时候为了结果的正确性和性能的提高,一定程度上牺牲了一些可读性。
-
多线程程序中debug的难度较大,有时候因为设计上的疏漏,需要在debug上花费很长的时间。
在本单元的学习中,我受益匪浅。多线程与单线程有很大的不同,虽然在这三周学习了许多关于多线程的设计和知识,但还有许多不了解的地方,希望能在以后更好的掌握多线程,设计出更好的架构。