OO-第二单元总结

第一次作业

类图

时序图

Main

RequestMonitor

RandomStrategy

NightStrategy

Elevator

设计思路

  • 线程

第一次作业创建了4了线程(除去绘图线程):主线程、请求监视器线程(RequestMonitor)、调度器线程(Strategy)、电梯线程(Elevator)。RequestMonitorStrategy共享RequestTableStrategyElevator共享ActionsQueue

  • 请求队列RequestTable

& 将请求根据方向、from楼层、to楼层分类。
imageriseRequestsdownRequests因设置了get方法产生了线程安全问题,在之后的作业中被替换为getKeys。
& RequestTable提供了synchronzied修饰的addRequestifHasgetIn方法,addRequest会唤醒在RequestTable对象等待的线程(调度器线程)。getIn方法调用了HashMapremove方法,所以调度器可以调用ifHas确定是否有需要的数据,使用getIn获取需要的数据并通过addRequest将多余的数据放回RequestTable,而无需考量同步问题。BUG: 在之后的多电梯作业中,由于我采用了一调度器一电梯的方式,导致某一调度器ifHasgetIn之间会出现所需数据被其他调度器线程抢占的可能,而调度器有时仅使用ifHas方法,所以两者的实现不能合并,因而需要在调度器中添加同步代码块。
& RequestTable维护了一个allOver布尔值代表新请求的终结,调度器通过调用noOneisAllOver方法来确认是否停止或等待。

  • ElevatorActionElevatorStatus

& 电梯运行状态、电梯运行动作的枚举imageimage

  • 动作队列ActionsQueue

& 主要维护两个FIFO队列,分别代表“已确认执行的电梯动作”、“动作所对应的请求”image方法addAction通过synchronzied修饰requestsaddPerson通过synchronized修饰persons,调度器通过这两个方法向动作队列中添加数据,并唤醒在ActionsQueue等待的线程(电梯线程)。方法getNextActiongetNextPerson与之对应,来使得电梯线程获取下一个动作。
& 维护一个allOver布尔值来代表新动作的终结。
& RandomStrategy每次向动作队列中添加动作时,需要唤醒电梯线程并等待电梯线程执行完所有动作。NightStrategy只在最后一次添加动作时唤醒电梯线程并终结。

  • RandomStrategy调度设计

通过makeNextAction确定主请求,在完成主请求的路程中每一层调用方法needOpen确认是否需要捎带或出电梯。主请求确认的逻辑:若电梯靠近低楼层,且低楼层存在请求,则以低楼层的某一请求为主请求,否则反之。

  • bug修复

& 因为RequestTablegetIn机制,某次使用该方法的时候忘记将多余的请求放回,导致请求丢失的情况。

第三次作页

类图

image

时序图

Main

StrategyController

RandomStrategy

Elevator

更改

  • RandomStrategyController

& RandomStrategyController共享RequestTable, 当有add请求的时候被唤醒,通过ElevatorFactory和不同的内部RandomStrategy类来创建调度器和电梯线程。

  • RandomStrategy

& 这次作业将调度器类修改为抽象类,其中抽象方法init用来初始化调度器的类型、最大载荷量,floors方法用来判断一个楼层是否是可达的,canOther方法用来判断一类请求是否可由更快的电梯单独完成,transferStation用来获取一个“不能由更快的电梯单独完成的请求”的“比不换乘更节省时间的换乘站”。具体实现在Controller类内部。

  • 多电梯设计方式

& 由Controller创建不同类型的调度器+电梯线程,实现不同的换乘逻辑,所有的调度器共享一个RequestTable对象,各线程通过canOther区分一个请求是否需要自己来完成,通过transferStation获取一个请求的换乘方案。

& 对于被一个电梯“看中”而未进入电梯的请求,将其存入RequestCache对象。
& 对于一个需要换乘的请求,通过HashMap将第二段请求保留,并在第一段请求完成时放入RequestTable

  • 可拓展性

& 通过工厂模式创建不同的电梯线程,将调度器类的关键逻辑(换乘逻辑,请求划分逻辑)放入抽象方法中,仅在有具体调度需求的时候实现,并通过内部类的模式,可以在不同的实现中互相调用不同调度器的方法实现,因而具有较好的拓展性。对于调度逻辑,仅需修改makeNextActionneedPeopleIn等少量关键方法即可。

  • bug修复

& 第三次作业遇到了一部电梯无限下行的bug,通过预先写好的assert很容易发现了bug所在!image

Hack方式

& 采用纯python脚本评测的方式,实现自动编译、打包、随机数据生成、数据合法性判断、jar包运行、正确性/运行时间检测、错误定位。
& 测试强度依赖于生成数据的逻辑,随机性比较强。

心得体会

由于本单元涉及到多线程编程,所以在第一次作业实现过程中遇到了各种各样的bug,后来重新巩固了涉及到的诸多概念,逐渐熟悉了多线程编程模式和调试方法,在后两次作业中基本上没有遇到线程上的bug。由于第一次作业中便考虑到了层次化设计,所以在之后的作业中修改起来比较容易。

posted on 2021-04-28 17:47  违规昵称#3141  阅读(48)  评论(0编辑  收藏  举报