OO第二单元总结

一、前言

  经历了第一单元表达式求导的磨砺,我终于是对面向对象编程有了懵懵懂懂的认识(动不动就重构确实不可取),而我们也来到了第二单元:多线程设计部分。本单元的作业是设计符合条件的电梯模型,自行设计电梯调度算法,在规定的时间把乘客送到地点,本次是实时请求,故需要采用多线程设计。接下来就对三次作业逐次分析一下。

二、程序分析

第一次作业

需求分析

  本次作业需求是设计单部可稍带电梯。即一部电梯,电梯无容量限制,性能不能低于ALS。

设计思路

  吸取第一单元的教训,我希望在第一次作业就尽力设计出可扩展性较高的程序,尽可能此后的作业在这次上迭代,而不是不断地重构。然后经过思考,线程方面:我主要用了三个线程,分别是输入线程,调度器线程和电梯线程。这里调度器线程虽然我构造了但并没有什么实际用处(在构造电梯时我把调度写在电梯内部了,写调度器时发现没有什么好写的,最后就只是个空壳留个后面使用了),采用了经典的生产者-消费者模式,输入线程与电梯线程的共享对象就是请求队列了,生产者输入线程不断地向请求队列中添加请求,消费者电梯线程从请求队列中抓取请求(调度算法采用的就是LOOK算法),输入停止后就结束输入线程,当请求队列为空且电梯内部队列为空且输入停止了就结束电梯线程。类方面:构造了Elevator类,Input类,Scheduler类就是线程方面的类,Main主类启动线程,Person类实现对请求的解读,Queue类即共享的请求队列。

UML类图

 UML时序图

复杂度分析

 

  这里可以看到爆红的都在Elevator中,主要是因为我的调度策略在电梯类内部,从而方法的复杂度有所提升。之后还是尽量避免把许多件事交给一个人来做吧。

第二次作业

需求分析

  本次作业与第一次作业相比,需求只是从单部电梯变成了一开始给定电梯数目然后容量有限制的多部电梯运行。

设计思路

  总体与第一次并无太多差距,只是把消费者的数目从一变为了多,在此次中我直接把原先的调度器类给删掉了,采用多部电梯竞争的模式,从请求队列中抓取请求。其他的第一次已有阐述,在此不再赘述。

UML类图

UML时序图

   与第一次基本一样,不再赘述

复杂度分析

 

  这里可以看出与第一次相比基本没差,依然是Elevator中的方法复杂度较高。

第三次作业

需求分析

 

  这次明显更有趣了,电梯分了三种类型,不同类型之间可以去的楼层,运行时间,容量都有了差异,并且还可以通过输入来动态增加电梯,确实难度提升了很多,尤其是在调度方面。

设计思路

  说实话,现在再来看我当时的设计确实存在着许多问题。首先电梯既然有三种类型,考虑到扩展性等我感觉可以利用工厂模式,应该建一个电梯的抽象类,然后三种电梯类型继承自该抽象类可能更有条理。然而我当时确实还保留了原来的Elevator类,只是创建了类型变量而已,这就使得Elevator类进一步臃肿了。由于具体架构还是沿袭着上一次的架构,所以我就谈谈部分细节方面的修改吧。首先是增加了End类和Safe类。这里主要是因为我的调度依旧是在电梯内部进行,然后我在第一次和第二次中结束线程的方法就不再适用了,这着实让我头疼了好一会儿,最后只好采用新建一个End类,每当不再有输入,并且请求队列也没有,自己电梯内部队列也为空时会在End类中修改一次一个标志变量(这里由于电梯的特殊性,有些乘客需要经过换乘才能到达目的地,所以有可能电梯还需要去接换乘的乘客,所以他还不能结束),只有当所有电梯都进行过修改后电梯才会结束线程。换乘是本次的一个特殊操作,我的方法是首先分析乘客是要坐哪两个类型的电梯进行换乘,在乘坐完第一个类型的电梯后,有一个标志位会被改变,然后该乘客的要求也会做一些改变(from变为他下电梯的楼层),接着重新投入请求队列中。当第二个类型的电梯来接他时根据标志位可以知道他是要换乘的并且已经坐完了第一趟。最后Safe类则是为了解决本次作业中提出的一个特殊要求,即输出不是线程安全的。Safe类就是专门封装的一个输出线程安全类。关于本次作业的性能方面,我几乎没有做太多的处理(中测时有小bug长时间没有解决,我也是有点慌,就先没在对性能方面做更多手脚了)。

UML类图

UML时序图

复杂度分析

 

  与前面有所不同的是input中有地方爆红了,这里是因为我在分析人的请求并设置标志位等比较复杂,然后又直接写到一个方法里了,不过我感觉这个是必要的了。

基于SOLID的分析

单一责任原则(SRP):

  整体的架构感觉不太满足,主要就是电梯与调度没有分离。

开闭原则(OCP):

  基本上是满足的,扩展性可以(我三次作业的基本架构并无较大变化,尽管扩展的代价可能使我的某些类变得巨大),但对内修改有点容易了,封装的不是很好。

可替换原则(LSP):

  在上面设计思路中已经谈到,在本次作业中没用到继承所以就不再考虑。

接口分离(ISP):

  本次作业没有设置接口不再考虑。

依赖反转原则(DIP):

  还是缺乏层次性结构,在功能方面基本无依赖关系。

 三、Bug分析与测试

  本单元测试中前两次作业均没有遇到BUG,在第三次作业中由于我自身的一些问题产生了一个令人哭笑不得的bug,可以说是思维上的漏洞吧,就是在电梯调度时修改方向会有时出现问题,导致电梯在两层之间往返,最后导致rtle(与死锁和死等没有关系),删掉两行之后也顺利通过修复。互测中由于我python不怎么会,互测时就以划水居多了(自己控制时间输入太困难了),除了第一次作业时用一个比较极端的数据hack了一位可怜的朋友,其他两次均没有hack成功了,之后要尽力像自动化测试靠拢,向大佬多多请教,提高自己的水平。

 

四、心得体会

  在本单元中我对多线程编程有了更深的了解,包括对线程安全方面的控制,共享对象加锁的处理等等。从第一次对多线程一脸懵逼,反复思考生产者与消费者模式的奥妙,再到现在能熟练解决一些简单的多线程问题,显然我是受益匪浅的。OO面向对象的编程思想可能我也正在有着更深的理解?毕竟这一单元我几乎就是迭代设计的,不用重构真是美滋滋,可能这就是拥有了良好扩展性的优势吧,希望以后我的理解可以更深,还要多向大佬们学习学习。

 

posted @ 2020-04-16 23:48  窜儿爱串儿  阅读(147)  评论(0编辑  收藏  举报