分析和总结自己三次作业的设计策略
在完成第一次作业对多线程理解的还不是很好,处于比较迷茫的转态,没有做到也没有理解指导书中所说的实时,对于电梯电梯调度算法实现的也不好,没有好好查阅资料,自己随随便便写了一个算法尽管能通过中测但是最后发现算法实现近似于FIFO,以上两点导致强测翻车;完成第二次作业进行了重构,将调度器作为输入线程和电梯线程的共享对象,调度器内部管理请求队列,采用sstf方法,电梯间没有调度,自由抢任务,主线程进行输入线程、电梯线程的创建和启动,电梯每到一个楼层调用调度器方法增加请求,并对调度器的方法进行一定的同步控制;第三次作业整体上没有太大的改动,将电梯线程的创建启动方法移动到调度器中,在调度器中将原来的queue替换为workqueue和waitqueue,将需要换乘的需求分为workqueue和waitqueue两部分,每当workqueue中的需求被满足,相应id的需求就从waitqueue中被移到workqueue中,同样的电梯间没有调度算法。
第三次作业架构设计的可扩展性
第三次作业设计的可扩展性尚可,功能设计方面各个类做到了各司其职,没有过度耦合的状况,性能设计方面没有考虑太多,每个电梯采用sstf算法,这样可能会导致某乘客等待时间过长,电梯之间没有特定的算法,电梯自己竞争资源,电梯的换乘方面采用静态策略,此种方法的灵活性会差一些,相关方面的扩展性可能较差。
SOLID 原则:
SRP:基本上满足,与第一次作业相比,类、方法的内部更好地实现了高内聚,分工更加明确。
OCP:不是很满足,代码的层次感不是很强,没有使用继承。
LSP:代码中没有使用继承。
ISP:代码中没有使用接口。
DIP:满足的不是很好,高层模块较高依赖底层模块,模块间的依赖没有通过接口实现。
基于度量来分析自己的程序结构
这次作业整体上架构没有太大变化,所以直接分析第三次代码。
这是代码的整体类图,直观感受为director类比较臃肿,实现的方法比较多,整体看上去还算整齐。
下面为对于复杂度的度量:
对各类中方法复杂度的度量:
input为单独一个线程对输入进行处理;director类进行调度,采用ssfs算法;每个elevator为一个单独的线程,与input线程一起共享director对象;divide类主要实现对输入请求的处理,如果输入请求不需要进行换乘,那么则原样返回请求,该请求装在链表中,若输入请求需要换乘,则返回链表——装有分解后的两个请求,director类再将其分别装入workqueue和waitqueue中并进行进一步的处理;output对提供的输出进行了线程安全控制;mainclass则依次创建、调用即可,其中queue类比较多余,提供的基本都是原容器的方法。
可以看到,出现复杂度爆表的方法分别是director类中的getdirection方法、task方法、divide类中的getdivided方法、elevator的moveonefloor方法,上述方法要么大量使用if else判断语句,要么进行了复杂的循环操作,这是应该避免的,这样可能导致程序出现意想不到的bug,并且理解起来也不十分容易。
以下是对各类依赖度的分析:
依赖程度上没有爆表,毕竟也没有复杂的依赖关系。
下面为时序图:
分析自己程序的bug
这单元作业完成状况比较惨烈,第一次、第二次作业通过了中测,但是强测全部翻车得到0分,第一次作业前文中提到是因为没有做到实时在线和调度算法太过垃圾,第二次翻车是因为System.in的问题,向电梯中增加乘客时条件没有控制好导致出现超载问题,调度算法移除请求时变量出错;第三次作业比较魔幻,第三次作业提交通过中测,并且这之后再次提交仍然通过,但是临近截止时我修改了一部分代码,就翻车了,导致这次作业是无效作业,本地跑样例是没有问题的,这仍然困惑着我,经过一些排除法初步判断是新电梯线程加入导致的问题。
发现别人程序bug
如前所述,这单元作业没有进入互测,不存在发现别人bug相关。
心得体会
这次多线程作业从编写、测试的角度讲,都有一定的难度,线程安全如果做不到的话就是灾难性的,这次的设计中对面向对象的体会更加深入了一些,这单元对于多线程的学习和理解感到比较吃力,自己完成的不是很理想,同时这次作业也让我认识到对程序的进行充分测试、实现自动化测试的必要性,不要抱有侥幸心理,永远不要觉得自己的程序没问题,尤其是多线程,并且在编程的初期就要尽最大可能保证正确性,不要总想着我会测出来bug等,这样耗时耗力还可能存在漏洞;总而言之,这单元再次让我真真实实地认识到了自己的菜,但是以后也会继续加油滴~。