BUAA_OO_第二单元

一、设计策略分析总结

  本单元实验要求对进阶难度的电梯进行模拟,要求模拟乘梯人员发出输入请求,且能够让电梯处理请求并模拟运行、开关门、将乘客送到目的地,在电梯做出相应行为时输出一定的信息。

  在本次任务中,我的设计原则是“一个类只做一类事”,同时几乎是按照现实生活中的电梯进行调度的设计。

(一)模块设计

  第一次作业中,经过分析并考虑可扩展性,将程序总体分为三个模块:输入请求处理,请求列表,电梯与电梯方向,调度器。其中请求列表为所有模块的共享变量,用于保存请求并供调度器获取;电梯与电梯方向模块中,前者只执行开门关门、上行下行以及进出人的操作,后者只是一个枚举类型,供电梯保存运行状态;输入请求处理使用了一个线程,将读到的请求插入请求列表,在读到NULL时将请求列表记录为结束并结束线程;调度器使用了一个线程,在这个模块中查找合适的请求,并控制电梯的运行。

  第二次作业中,在电梯与电梯方向模块里增加了楼层类,主要作用是将可能存在空缺的可用楼层映射到1-n的连续数字,并且记录每个楼层是否有乘客的目的地。

  第三次作业中,增加了换乘人员及其列表模块,记录需要换乘的人和换乘路线。

  三次作业均只有主线程、输入请求线程及调度器线程三种。

(二)调度算法设计

单电梯调度算法:

初始化:当电梯状态为停止且请求列表中存在该电梯能够运送的请求时,获取第一个可用请求,并将方向设为前往该请求请求楼层的方向,目标楼层设为请求楼层。

目标楼层:当前电梯方向中,据当前楼层最近的楼层。

  每到达一层楼,判断该楼层是否有出电梯的请求和同方向进电梯的请求,若有则开门出人,并在能够进入的情况下(目前仅有容量限制导致不能进入)进入所有该层请求的人(包括同方向和异方向),重新计算目标楼层。继续向目标楼层前进。

  电梯到达目标楼层时,转换方向,若存在该方向的目标楼层继续前进,否则查看请求列表确定目标楼层。如果列表里也没有合适的,那么电梯状态设为停止,调度器进入wait状态。

多电梯调度算法:

  三个电梯调度器分别对满足自己运送条件的请求进行竞争,设置三种换乘:到达15层以上的在15层换乘、上行且需要到3层的在5层换乘,其余需要换乘的在1层换乘。

二、基于度量分析程序结构

指标说明:

  • LOC: Line of Code

  • NCLOC:Non-Commented Line Of Code

  • ev(G) 基本复杂度(Essential Complexity):衡量程序非结构化程度。

  • iv(G) 模块设计复杂度(Module Design Complexity):衡量模块判定结构,即模块和其他模块的调用关系。

  • v(G) 圈复杂度(Cyclomatic Complexity):衡量一个模块判定结构的复杂程度,数量上表现为独立路径的条数

(一)第一次作业

1.代码规模

类名LOCNCLOC
Main1313
Dispatcher6464
Elevator7777
ElevatorDirection1313
RequestInput3029
RequestList3535
总计232231

2.类的属性方法

调度器:

        

         在线程中不断调用lookforReq()方法,若无请求则进入wait状态或者结束线程。

 电梯方向:  

        

  对电梯的运行方向的枚举,上行下行或者处于暂停状态。reverse函数用于转换方向。

输入请求:

        

请求列表:

        

       涉及的所有操作均需要锁住,当读取到NULL时设为over。

 电梯:

         

     将电梯的一系列操作细分为一个个小方法,如开门关门,进人出人,并能记录电梯内部人员的请求。

3.度量

  

  可看出复杂程度较高的,主要为调度器中的查找请求的方法。这是将对电梯的所有操作都用一个方法来表示造成的。

4.类图

        

  使用单例模式,主线程创建请求输入线程和调度器线程,一个调度器控制一个电梯实例。

(二)第二次作业

1.代码规模

类名LOCNCLOC
Main1212
Dispatcher138135
Elevator9696
ElevatorDirection1313
FloorList5151
RequestInput3029
RequestList3535
总计380376

  与第一次作业相比,更改只出现在调度器、电梯及楼层类中。

2.类的属性方法

调度器: 

  

  调度器中,为了满足更优的调度算法,增加了若干关于请求的计算,其中findUppFloor()和findDownFloor()函数是为了寻找当前方向上的目标楼层。

楼层:

  

  doors数组类似于生活中电梯内部的表盘,记录哪一层有人要下电梯。

  getIndex() 用于转换不规则楼层信息与规则的序列。

3.度量

  同样也是一些起到控制作用的函数具有较高的复杂度。

4.类图

  

  依然是单例模式,主线程创建输入请求线程和调度器线程,一个调度器对应一个电梯实例及相应的楼层实例。

(三)第三次作业

1.代码规模

类名LOCNCLOC
Main1717
Dispatcher194189
Elevator137137
EleDirect1313
FloorList6666
RequestInput4443
RequestList3333
Person7575
PersonList3232
总计611605

  由于出现换乘的可能性,故增加人员列表导致了大部分类都发生一部分改变,在调度方面区别不大。

2.类的属性方法

 人员:

  

  对每一个人的请求创建每一个人的类,当需要换乘时才会对这个人进行下一步操作,不然就不用管了按前两次作业的处理来。

  divideReq() 为将该人的请求拆分成两个可达的请求,当第一个请求完成时,向请求列表中插入第二条请求。

换乘人员列表:

  

  如果没有换乘人员,那么一直空着。对该表的操作也是都应该加锁的。

3.度量

  感觉复杂度高的都是逻辑比较复杂的,其中牵扯到的操作比较多,看了看也不太好修改。

4.类图

  

   要比前两次的结构复杂,但是其实把RequestList换成PersonList,一直用后者操作也可以,但是那样需要改的比较多,怕改着改着出现问题(懒)。于是只简单增加了换乘人员类,各个类中增加部分语句即可。

(四)UML协作图

  本单元程序均只有三个线程,故三次作业UML协作图可统一展示。

 

(五)分析改进

1.优缺点分析

  优点:结构比较明确,电梯运行与控制分离;模块化,增加功能时只需要改变一部分,省时省力。

  缺点:存在冗余的情况,如Person类可继承PersonRequest类,但只重新建了个并重复的部分功能。

2.SOLID设计原则改进

  • Single Responsibility Principle(单一职责原则):每个方法基本上都只负责一项功能的执行,避免一个类做太多事情,符合。

  • Open Close Principle(开放封闭原则):除了调度算法整个更新以外,其他都是简单增加一部分方法代码,很少重构现象的发生,符合。

  • Liscov Substitution Principle(里氏替换原则):不存在子类的设计,符合。

  • Interface Segregation Principle(接口分离原则):不存在接口设计,符合。

  • Dependency Inversion Principle(依赖倒置原则):若增加新的电梯,只需要在FloorList中增加对应电梯的ID的信息,抽象程度较好。

三、错误分析

(一)存在错误

  在前两次作业中,处理好输入的结束并且把对共享变量的操作都加上锁之后,应该就没有线程上的bug了。

  第三次作业中,出现了CPU超时的情况,原因是判断wait的条件为“请求列表为空且电梯内为空”,但存在“请求列表不为空,但是请求该电梯不能满足”的情况,导致了这个调度器一直在轮询,从而超时。

  还有无法中断的情况,在前两次作业中,输入NULL时请求列表会设为状态结束,此时会唤醒一次所有线程,如果电梯wait了,会被唤醒并判断结束,终止线程。但第三次作业中,请求输入结束了,但是如果有换乘的,换乘完会插入请求列表,调度器判断进入wait状态,由于不再有变化,导致线程无法再次被唤醒并且一直wait下去。这需要考虑终止的各种情况。

 

(二)测试的方法

 1. 手工测试

  如对NULL的插入位置依次尝试。

 2. 自动测试

  编写java程序,自动生成测试样例,读取测试并按时间延时输出模仿手工输入,并检查输出结果,记录下错误的测试数据及结果供日后debug。

四、心得体会

  做电梯最重要的是理解多线程的思想,理解了之后程序便比较容易编写了,同时也能够知道莫名的bug出现位置的可能性。

  另一方面,计组中学到的工程化思想得到了应用,第一次作业时参考去年的电梯作业要求用了一天的时间进行设计,在后两周效果还不错,虽然性能分不算高,但是付出与收获的性价比很高…

转载于:https://www.cnblogs.com/palaipaqu/p/10739647.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值