OO第二单元总结

 

前言:

本单元的作业是电梯合集,傻瓜调度、ALS捎带以及多部智能调度电梯。傻瓜调度的核心是每次只能处理一个请求,且为最先到达的请求;ALS捎带则为相对主请求可捎带的(有点儿傻)电梯,可捎带原则为,发出的请求楼层与主请求楼层为当前楼层的同一侧;多部智能调度电梯则为多部电梯可同时运行,并加入电梯容量、电梯可停靠楼层、运行速度等独立属性,以及中转转乘机制。综合来看,本单元主要是对多线程及线程安全的考察。这次相比之前多加了输入输出借口,输入不用像第一单元那样魔鬼处理(wf判定)了,并且输出是一种新的带有时间戳的形式,且程序运行时间暴涨,评测机压力直线上升(滑稽)

一、三次作业具体分析

第一次作业:

1、设计策略

第一次作业较为简单,所以设计的较为简单,除MainClass类外,仅有一个线程类Elevator。

MainClass类为循环读入PersonRequest,并将请求的目标楼层(不涉及捎带等其他要求,且为逐个处理,故不用考虑请求楼层)放入等待队列list,并以参数形式传给Elevator类:

 1 public class MainClass {
 2     public static void main(String[] args) throws IOException {
 3         List<Integer> list = new ArrayList<>();
 4         ElevatorInput elevatorInput = new ElevatorInput(System.in);
 5         while (true) {
 6             PersonRequest request = elevatorInput.nextPersonRequest();
 7             if (request == null) {
 8                 break;
 9             } else {
10                 Elevator elevator = new Elevator();
11                 elevator.getFactors(
12                         request.getFromFloor(),
13                         request.getToFloor(),
14                         request.getPersonId());
15                 elevator.getList(list);
16                 elevator.run();
17                 list.add(request.getToFloor());
18             }
19         }
20         elevatorInput.close();
21     }
22 }

然后在Elevator类中对出入电梯以及更改楼层进行模拟,利用sleep方法模拟所需时间:

1   private void spend(long time) {
2         try {
3             Thread.sleep(time);
4         } catch (InterruptedException e) {
5             e.printStackTrace();
6         }
7     }

只是在起始楼层非1时以及处理完当前请求并更改楼层到下一请求时有些许处理,其他并无难点。

2、方法复杂度等分析

通过相关数据可知本次作业较为简单,方法的循环使用也较少,所以代码复杂度较低,内部的耦合性很低

3、类图

可知类间关系很简单,代码架构十分清晰,主要由Elevator类去处理请求并输出。

第二次作业:

1、设计策略

 第二次作业,为了更好地处理请求队列,增加了一个Work线程作为读入线程,Elevator类保留,即读与处理同时进行,从而更好地处理主请求和捎带。

MainClass类仅作为两个线程的启动器:

1 public class MainClass {
2     public static void main(String[] args) {
3         ArrayList<PersonRequest> list = new ArrayList<>();
4         Work work = new Work(list);
5         Elevator elevator = new Elevator(list);
6         work.start();
7         elevator.start();
8     }
9 }

请求队列作为输入类和处理类共享队列,输入负责add,处理在达到读取请求后,并将其放入电梯后,remove。

这次主要变动的是Elevator类为了处理主请求,新增了inList列表用于储存已进入电梯但未到达目标楼层的请求,主请求则为inList.get(0),即最先到达电梯的请求。

1     private int getInLoop(int i) {
2         int j = i;
3         TimableOutput.println("IN-" + list.get(j).getPersonId()
4                 + "-" + curFloor);
5         inlist.add(list.get(j));
6         list.remove(j);
7         j--;
8         return j;
9     }

当请求进入电梯后,将其从总请求队列List里删除,加到inList中,然后在inElevator方法中循环判断,满足条件则进入电梯。条件中不仅要满足发出请求楼层为当前楼层,还要满足该请求和电梯内主请求是否满足捎带原则(如果电梯内无人,则直接进入就ok),代码如下:

 1     private void carryAno() {
 2         int i;
 3         if (list.size() > 0) {
 4             for (i = 0; i < list.size(); i++) {
 5                 if (list.get(i) != null) {
 6                     if (list.get(i).getFromFloor() == curFloor) {
 7                         if (inlist.isEmpty()) {
 8                             flag = 1;
 9                             inElevator();
10                         } else if (getIfcarry(i)) {
11                             inElevator();
12                         }
13                     }
14                 }
15             }
16         }
17     }

有个需要注意的点就是,在笔者的架构下,电梯在开关门间需满足先下后上原则,这样主请求的判定才正确。

2、方法复杂度

这次的方法中changeFloor区分了出发楼层和目标楼层是否同正负的情况,如果异号,那么需要在循环时跳过0层,所以代码较为重复和冗长。inElevator和run方法中循环比较多,新增判断变量加入了不少,涉及较多边界条件的处理,因而复杂度较高。整体来看,方法复杂度适中。

3、类图

架构比较简单,work类读入与Elevator类处理同时进行。

第三次作业:

1、设计策略

本次为3部容量、运行速度、停靠楼层均不同的电梯同时运行,且存在中转情况,因而加入了调度器负责分析请求并下发给电梯请求以及Newre类用于重写PersonRequest类,用于需中转乘客在到达中转楼层的请求变更。

Newre类,携带原本的 PersonRequest,并新加from和to用于记录到达中转站后的请求变更:

 1 public class Newre {
 2     private PersonRequest request;
 3     private int from;
 4     private int to;
 5 
 6     public Newre(PersonRequest request,int from,int to) {
 7         this.request = request;
 8         this.from = from;
 9         this.to = to;
10     }
11 
12     public int getFrom() {
13         return from;
14     }
15 
16     public int getTo() {
17         return to;
18     }
19 
20     public int getId() {
21         return request.getPersonId();
22     }
23 
24     public PersonRequest getRequest() {
25         return request;
26     }
27 
28     public void setFrom(int from) {
29         this.from = from;
30     }
31 
32     public void setTo(int to) {
33         this.to = to;
34     }
35 }

每当用户到达目的楼层时,判断其最初请求的目标楼层与Newre记录的to是否相同,不同则为中转乘客,并进行请求变更加入到总请求队列中等待分配:

1                if (inlist.get(i).getTo() != to) {
2                     inlist.get(i).setFrom(curFloor);
3                     inlist.get(i).setTo(to);
4                     addRequest(inlist.get(i));
5                 }            

中转乘客中转楼层的确定在调度器中,当请求的from和to不能由一个电梯完成时,遍历-3到20层确定中转楼层(初始携带电梯与中转后电梯须有公共楼层,且to在中转电梯的可停靠楼层中)

需要注意的点是程序结束的标志是总请求队列读取到null且3部电梯的请求队列均为空,且都关上了门(关门的事儿别问为什么知道的)

2、方法复杂度

较为复杂的方法均集中于调度器,说明调度器的方法需要进一步拆分优化,调度算法复杂度有点儿小高(还是太菜惹

3、类图

多加了一个调度器线程,用于实时监控总请求队列和分发请求,三部电梯利用Elevator类建3个就完事儿了

 1 public class MainClass {
 2     public static void main(String[] args) {
 3         List<Newre> list = new ArrayList<>();
 4 
 5         List<Integer> astList =
 6                 Arrays.asList(-3,-2,-1,1,15,16,17,18,19,20);
 7         List<Integer> bstList =
 8                 Arrays.asList(-2,-1,1,2,4,5,6,7,8,9,10,11,12,13,14,15);
 9         List<Integer> cstList =
10                 Arrays.asList(1,3,5,7,9,11,13,15);
11         Queue queue = new Queue(list);
12         Elevator elevator1 = new Elevator(6,400,'A',astList,list);
13         Elevator elevator2 = new Elevator(8,500,'B',bstList,list);
14         Elevator elevator3 = new Elevator(7,600,'C',cstList,list);
15         Distribute distribute =
16                 new Distribute(elevator1,elevator2,elevator3,list);
17         queue.start();
18         distribute.start();
19         elevator1.start();
20         elevator2.start();
21         elevator3.start();
22     }
23 }

二、bug分析及修复

互测时他人出的bug多是手残或者边界条件考虑不全,我的bug也是集中在边界条件的考虑上。

我是利用自己根据边界条件造几组数据进行测试的,比如程序结束的判断上,不能只关心队列是否已空,还要确保电梯门都关了(颓废

bug Hunter提醒您:边界条件不注意,强测挂一片

三、心得体会

这个单元的作业在时序上要求要高不少,生产者消费者模型、多线程蛮有趣的,比某多项式求导有意思多了(逃

希望能学习大佬第三次作业的架构和调度算法,让我的电梯智商再高点儿~

posted @ 2019-04-23 12:09  17373450  阅读(167)  评论(0编辑  收藏  举报