第一次作业
-
作业分析
本次作业任务:单部多线程可稍带。
本次作业的难点主要在于第一次接触多线程思想,对其的理解以及实现。实现并不困难,主要是两个线程的运行:
- Input,输入新增的电梯请求。
- Elevator,完成已经申请的电梯请求。
通过以上两个线程,完成对于等待队列的维护(确保线程安全),即可达到本次作业的目的。
另外,因为本次作业要求实现可稍带的功能,所以我选择了相对容易实现的LOOK算法。通过判断某方向是否存在请求,实现可稍带原则。
-
UML图
由上图可见,本次作业的低耦合效果并不是很差,也实现了通过两个线程维护队列的目的。
-
度量分析
Method | ev(G) | iv(G) | V(G |
---|---|---|---|
Elevator.checkInOut() | 5 | 4 | 6 |
Elevator.Elevator(Queue) | 1 | 1 | 1 |
Elevator.getArrayList() | 1 | 1 | 1 |
Elevator.getArrayList() | 1 | 1 | 1 |
Elevator.getDir() | 1 | 1 | 1 |
Elevator.getFloor() | 1 | 1 | 1 |
Elevator.getInOut() | 1 | 2 | 2 |
Elevator.getTo() | 1 | 1 | 1 |
Elevator.isEmpty() | 1 | 1 | 1 |
Elevator.move() | 1 | 3 | 3 |
Elevator.personAdd() | 1 | 4 | 4 |
Elevator.personRemove() | 1 | 3 | 3 |
Elevator.run() | 1 | 6 | 6 |
Elevator.setTo(int) | 1 | 1 | 1 |
Input.Input(Queue) | 1 | 1 | 1 |
Input.isEnd() | 1 | 1 | 1 |
Input.run() | 3 | 4 | 4 |
Output.arrive(int) | 1 | 1 | 1 |
Output.close(int) | 1 | 1 | 1 |
Output.open(int) | 1 | 1 | 1 |
Output.sleep(int) | 1 | 1 | 1 |
Person.getDir() | 1 | 1 | 1 |
Person.getFrom() | 1 | 1 | 1 |
Person.getId() | 1 | 1 | 1 |
Person.getTo() | 1 | 1 | 1 |
Person.person(String) | 1 | 1 | 1 |
Queue.get(Elevator) | 1 | 12 | 12 |
Queue.getArrayList() | 1 | 1 | 1 |
Queue.isEmpty() | 1 | 1 | 1 |
Queue.put(Person) | 1 | 1 | 1 |
Queue.Queue() | 1 | 1 | 1 |
Queue.test() | 1 | 1 | 1 |
Queue.waitQueue(Elevator) | 1 | 1 | 1 |
Average | 1.17 | 1.97 | 2.06 |
Class | OCavg | WMC |
---|---|---|
Elevator | 1.92 | 25 |
Input | 1.67 | 5 |
Output | 1.00 | 6 |
Person | 1.20 | 6 |
Queue | 2.00 | 14 |
Task1 | 1.00 | 1 |
Average | 1.63 | 9.50 |
从两张度量分析表可以看出高内聚是各种意义上的做到了orz,但是显然很多方法的复杂度太高、可维护性太低,十分不利于后续的迭代。
- 测试&BUG&互测
-
在完成程序的设计以及实现之后,就是进行数据的测试,寻找bug:
- 测试指导书给出的样例。
- 测试数据范围的特殊情况、边界条件。
- 结合python、批文件处理进行数据的覆盖测试。
-
本次作业再中测、强测中并未测出任何bug。但是再互测中,由于一个细节问题导致电梯在判断是否在该楼层停留时,会存在一个极其短暂的无法获得对应请求的过程,我就被砍了一刀。其实归根到底还是代码实现时的不细致,以及本次评测机搭建的问题。
-
在进行互测时,基本步骤与自我的bug检测相差无二。同时,也拜读了不少同学的优秀代码。
-
第二次作业
-
作业分析
本次作业任务:多部多线程可稍带调度电梯的模拟。
很显然,第二次作业只是第一次作业的简单升级,我们只需要在第一次作业的基础上做一些简单的处理就可以得到第二次作业的代码实现。
- 电梯名以及电梯的数量。
- 电梯的容量。
- 电梯可访问的新增楼层。
- 人员乘坐的电梯分配。
第一次作业是一对一的生产者消费模型的话,本次作业就是一对多模型, 由于有着第一次作业的现成代码,我就直接在第一次作业的基础上,新增了一个电梯请求的均分原则直接完成(其实是懒)。
-
UML图
从UML图也可以直观看出,本次作业就是第一次作业的拓展。不论是架构、内容等方面都与第一次作业大体一致,耦合性较低。
-
度量分析
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
Elevator.checkInOut() | 5 | 5 | 7 |
Elevator.Elevator(char, int, int) | 1 | 1 | 1 |
Elevator.getDir() | 1 | 1 | 1 |
Elevator.getFloor() | 1 | 1 | 1 |
Elevator.getInOut() | 1 | 2 | 2 |
Elevator.getPersonArrayList() | 1 | 1 | 1 |
Elevator.getTo() | 1 | 1 | 1 |
Elevator.isEmpty() | 1 | 1 | 1 |
Elevator.move() | 1 | 4 | 5 |
Elevator.personAdd() | 1 | 5 | 5 |
Elevator.personRemove() | 1 | 3 | 3 |
Elevator.run() | 1 | 6 | 6 |
Elevator.setArrayList(ArratLIst) | 1 | 1 | 1 |
Elevator.setDir(int) | 1 | 1 | 1 |
Elevator.setFloor(int) | 1 | 1 | 1 |
Elevator.setTo(int) | 1 | 1 | 1 |
Input.chooseQueue(int) | 1 | 1 | 1 |
Input.Input(ArrayList |
1 | 1 | 1 |
Input.run() | 3 | 5 | 5 |
Output.arrive(int, int, char) | 1 | 1 | 1 |
Output.close(int, char) | 1 | 1 | 1 |
Output.in(int, int, char) | 1 | 1 | 1 |
Output.open(int, char) | 1 | 1 | 1 |
Output.out(int, int, char) | 1 | 1 | 1 |
Person.getDir() | 1 | 1 | 1 |
Person.getFrom() | 1 | 1 | 1 |
Person.getId() | 1 | 1 | 1 |
Person.getTo() | 1 | 1 | 1 |
Person.Person(int, int, int) | 1 | 1 | 2 |
Person.setFrom(int) | 1 | 1 | 1 |
Person.setId(int) | 1 | 1 | 1 |
Person.setTo(int) | 1 | 1 | 1 |
Queue.get(Elevator) | 1 | 13 | 13 |
Queue.inputEnd() | 1 | 1 | 1 |
Queue.isEmpty() | 1 | 1 | 1 |
Queue.put(Person) | 1 | 1 | 1 |
Queue.Queue() | 1 | 1 | 1 |
Task2.main(String[]) | 1 | 3 | 3 |
Average | 1.14 | 1.98 | 2.07 |
Class | OCavg | WMC |
---|---|---|
Elevator | 1.88 | 30 |
Input | 1.75 | 7 |
Output | 1.00 | 5 |
Person | 1.11 | 10 |
Queue | 2.14 | 15 |
Task2 | 3.00 | 3 |
Average | 1.67 | 11.67 |
由于本次作业只是第一次作业的一个简单迭代,显然其度量的统计结果实际上与第一次作业是相差不大的,问题同样是在于部分方法复杂度较高,不利于后续迭代。
- 测试&BUG&互测
-
在完成程序的设计以及实现之后,就是进行数据的测试,寻找bug:
- 测试指导书给出的样例。
- 测试数据范围的特殊情况、边界条件。
- 结合python、批文件处理进行数据的覆盖测试。
-
本次作业中,强测出现了bug,是我没有想到的,简直是震惊。本以为课下做足测试,但还是不曾想到在强测仍然被刀了一次,且本地无法复现,导致了我真正意义上地开始重视起来多线程,经过仔细排查,才发现在访问某一方法时,并未上锁,又是细节问题(枯了orz)。
-
在进行互测时,基本步骤与自我的bug检测相差无二。但是在拜读了同学代码之后,也学会了不少神奇的操作。
-
第三次作业
-
作业分析
本次作业任务:多部多线程可稍带调度电梯的模拟
第三次作业仍然是第二次作业的升级,但是这次的跨度显然比之前的跨度更大。
- 对电梯类别及其属性上做了划分。
- 新增增加电梯的指令。
- 引入了电梯换乘的概念。
其实,仔细分析,本次作业仍然可以采用前两次作业的架构。与其一味地纠结于电梯的停靠楼层,不如将其转换为Person类的属性。在Input类输入请求时,就通过辅助算法,确定其中转楼层以及换乘电梯名,这样也就不必考虑更换电梯的运行模式。但是因为存在请求的二次申请,我在第二次作业的基础上写了一个Schedule类,完成对请求的分配。
-
UML图
不难看出,本次作业就是第二次作业的一个简单迭代。架构仍然是采用了前两次作业的架构。
-
度量分析
Method ev(G) iv(G) v(G) Check.checkFloor(int, int) 3 1 3 Check.checkTransfer(Person) 8 15 21 Elevator.checkInOut() 9 11 15 Elevator.Elevator(String, String, Queue) 1 1 1 Elevator.getCapacity() 1 1 1 Elevator.getDir() 1 1 1 Elevator.getFloor() 1 1 1 Elevator.getInOut() 1 2 2 Elevator.getMoveTime() 1 1 1 Elevator.getPeresonArrayList() 1 1 1 Elevator.getTo() 1 1 1 Elevator.getTransferArrayList() 1 1 1 Elevator.getTransferArrayList() 1 1 1 Elevator.getType() 1 1 1 Elevator.hasTransfer() 3 2 3 Elevator.isEmpty() 1 2 2 Elevator.move() 1 4 5 Elevator.personAdd() 1 9 9 Elevator.personRemove() 1 5 5 Elevator.run() 1 7 7 Elevator.setCapacity(int) 1 1 1 Elevator.setDir(int) 1 1 1 Elevator.setFloor(int) 1 1 1 Elevator.setMoveTime(int) 1 1 1 Elevator.setTo(int) 1 1 1 ElevatorGroup.addElevator(Elevator, Queue) 1 1 1 ElevatorGroup.addPerson(Person) 1 1 1 ElevatorGroup.ElevatorGroup(String, int, int) 1 1 1 ElevatorGroup.getCapacity() 1 1 1 ElevatorGroup.getElevatorArrayList() 1 1 1 ElevatorGroup.getMoveTime() 1 1 1 ElevatorGroup.getQueueArrayList() 1 1 1 ElevatorGroup.getType() 1 1 1 ElevatorGroup.hasTransfer() 3 2 3 Input.Input(Schedule) 1 1 1 Input.isStop() 1 1 1 Input.run() 3 6 6 Output.arrive(int, int, String) 1 1 1 Output.close(int, String) 1 1 1 Output.in(int, int, String) 1 1 1 Output.open(int, String) 1 1 1 Output.out(int, int, String) 1 1 1 Person.getDir() 1 1 1 Person.getElevatorType() 1 1 1 Person.getFrom() 1 1 1 Person.getId() 1 1 1 Person.getTo() 1 1 1 Person.getTransferDir() 1 1 1 Person.getTransferElevatorType() 1 1 1 Person.getTransferTo() 1 1 1 Person.isTransfer() 1 1 1 Person.Person(int, int, int, Schedule) 1 1 2 Person.setDir(int) 1 1 1 Person.setElevatorType(String) 1 1 1 Person.setId(int) 1 1 1 Person,setTo(int) 1 1 1 Person.setTransfer(boolean) 1 1 1 Person.setTransferDir(int) 1 1 1 Person.setTransferTo(int) 1 1 1 Person.trans() 1 1 1 Queue.get(Elevator) 1 23 23 Queue.getPersonArrayList() 1 1 1 Queue.isEmpty 1 1 1 Queue.put(Person) 1 1 1 Queue.Queue() 1 1 1 Queue.scheduleEnd() 1 1 1 Schedule.addElevator(Elevator, Queue) 3 3 3 Schedule.addPerson(Person) 1 1 1 Schedule.getTransferNum() 1 1 1 Schedule.hasTransfer() 1 1 1 Schedule.inputEnd() 1 1 1 Schedule.isEmpty() 1 1 1 Schedule.isStop() 1 1 1 Schedule.run() 3 18 18 Schedule.Schedule(ArrayList ) 1 1 1 Schdule.setTransferNum(int) 1 1 1 Schedule.setTransferNum(int) 1 1 1 Task.main(String[]) 1 1 1 Average 1.34 2.25 2.46 Class OCavg WMC Check 8.00 16 Elevator 2.05 45 ElevatorGroup 1.22 11 Input 2.33 7 Output 1.00 5 Person 1.05 21 Queue 2.71 19 Schedule 2.20 22 Task 1.00 1 Average 1.86 16.33 -
测试&BUG&互测
- 本次作业,由于种种原因并未搭建对应的评测机,采取了一定的手动数据评测,当然,这种评测是不全面的。
- 在本次作业中,强测被砍了一刀,互测被砍了两刀。课下才发现又是细节问题(我吐了,想给自己一刀),原因是在电梯类中,我存了两个队列:直达队列以及换乘队列,但是在判断人数时,只计算了直达队列的人数,导致被hack,实在是不应该。
- 在互测过程中,主要依靠的就是自我测试中的保存数据。
总结
回顾第二单元的作业,的确能够感受到多线程与单线程的天差地别,一个简简单单的数据访问也是别有洞天。但多线程也的的确确有着独特的魅力,更能给我一种代入感,使得编程更加“具象化”(虽然也有不少让人费脑的线程安全问题)。
总的来说,自己很不满意这一单元的作业。无论是实际得分,还是互测过程。自己的状态、态度都比不上第一单元,尤其时本单元的bug往往出现在一些细节上,真是让人汗颜。这些都是能且容易避免的,但还是栽在上面了,确实有些说不通。当然,也有一些自己满意的地方:能在一定程度上用面向对象的思维进行思考、编程;尝试在编程前进行了一些架构设计;完成三次作业的迭代开发……
体会
OO课程可以说已经过半了,自己倒是有了不少体会。第二单元的作业完成情况不如第一单元,自己的状态、态度也比不上第一单元,第一单元想得是尽量拿满分,而这一单元却只想着完成作业,属实不该。两个单元的各个方面都是鲜明的对比。希望自己能够及时调整状态吧,恢复到第一单元的状态,甚至更好。就像上一次作业所说的那般,能够好好享受这个过程吧。
NO OO NO LIFE!