oo第二单元总结
oo第二单元总结
一、概述
本单元的作业内容主要为通过多线程调控来实现电梯调度。相较于上一单元,本单元的重点在于保证多线程的安全性以及遵循设计的SOLID原则来设计程序。整体来看,本单元作业的完成情况比上一单元要好,没有进行大的重构,强测互测也未出现bug,这点是值得肯定的。不足之处还是在于调度策略的优化上没有下足功夫,导致第二次作业的性能分不理想;没有很好地遵循SOLID的设计原则,有些类设计的不好。
二、设计策略分析
从多线程设计角度采取了最普通的生产者-消费者模式,这个没什么特别要说的。捎带策略全程采用ALS。对于电梯的运行则采取了有限状态机的想法,提取电梯5种状态:
status0:电梯初始状态
status1:电梯上行
status2:电梯下行
status3:电梯停靠且有人进出电梯(电梯门需要开、关)
status4:请求全部完成,电梯结束运行
通过实现这五种状态之间的转换来实现电梯线程。下面具体从每一次作业来看设计策略。
第一次作业:单个电梯
第一次作业整体设计比较简单,只需要一个生产者线程,一个充当请求队列的调度器(实际上没有调度功能),以及一个电梯线程。电梯的运行策略是,如果电梯内有请求,则优先处理电梯内请求;否则则接收电梯外最早到达的请求并执行,如果没有请求,则电梯停在最后完成请求的楼层不变。
第二次作业:多个电梯
第二次作业相较于第一次作业,增加了电梯的数量,且电梯有搭乘上限,这次作业的调度器就需要起到调度的作用了。因为没有想到较好的调度策略,就简单暴力地将接收到的请求平分给所有电梯,这样由于无法有效的捎带,导致性能下降许多,如果将平分改为自由竞争同一个请求队列,性能应该会有所上升。
第三次作业:多个不同类型电梯
第三次作业相较于第二次作业,增加了不同类型的电梯,且由于不同类型电梯所能到达的楼层不同,中间需要换乘。由于第三次作业性能的考核增加了每个乘客需要等待的时间,而无意义的换乘会大大增加等待时间。因此本次作业的调度器对请求进行了分离,将不需要换乘的请求分配到对应类型的电梯里,由该类型的所有电梯进行自由竞争。需要换乘的请求则在固定的层数换乘,方便调度。这次作业的性能分较第二次有很大提升。
三、第三次作业架构设计的扩展性
第三次作业的基本架构仍是生产者-消费者模式,在三次作业的迭代过程中,对电梯类的扩展非常大,每次都会为电梯类增加新的属性,这样是没有遵循SRP以及OCP原则的。应该将电梯类更加细分,将一些具体的操作独立成类,减轻电梯类的负担。
四、基于度量的程序分析
第一次作业
第二次作业
第三次作业
分析三次作业的类图不难看出,程序的整体架构并没有发生大的改变,前两次作业在架构上甚至完全相同。但是在分析类以及各个方法的复杂度后就不难发现,由于电梯类内包含电梯状态变化的有限状态机,电梯类的部分方法基本圈复杂度很高,且随着电梯要求的增高,电梯内的方法也越来越多。之前在扩展性分析中也提到,这样是有悖于SOLID原则的设计。应当将电梯类的功能细分为多个类,使电梯类不那么冗杂。
五、bug分析
本单元作业未出现bug。在与同学的交流中发现,这位同学在第三次作业中将三种电梯分别成类,并在属性中相互包含,这使得线程运行时发生死锁。相比较性能还是更应该优先考虑正确性。
六、心得体会
本单元相比较上一单元而言,在迭代开发上感觉没有那么困难了。本单元开始第一次作业的时候是感觉最难的时候,因为对于多线程的理解不够明白,电梯的调度也不太会实现。后两次作业相较于第一次作业,心理压力明显小了很多。
比较幸运的是,尽管电梯写的过于复杂,在测试中也没有出现bug。
本单元主要收获是:了解了多线程的安全问题以及程序设计的原则(尽管未能很好的体现在作业上)