第二单元实验博客

1、多线程的协同和同步控制

我在三次作业中都采用了最基本的生产者—消费者模式,几乎可以说是没有进行任何改动。

整体上结构分为三部分,Producer线程,Elevator线程,buffer缓冲区。把所有需要线程共享的数据都放在buffer中,Elevator的数据只允许线程自己操作,其他线程只能读取,不能修改,事实上我也在尽量避免其他线程读取Elevator数据。

这样一来有这么几个好处。首先,只有一个对象会被多个线程修改,这样只需要给buffer的方法加锁就足够了。只有一个对象有锁,从根本上避免了死锁的可能性。第二,结构上与生产者—消费者模式保持一致,使用传统的设计模式,避免了其他可能的多线程错误。

当然也有一些缺点,比如由于每个Elevator的内部数据都避免其他线程读取,所以没有办法从群体控制的角度去考虑调度算法,这是结构上对于性能的限制,不过就结果来看即使不考虑群控算法,性能也不会太差。再比如电梯从buffer中获得的信息可能有很多种,不只是一个PersonRequest。我对此的解决办法是建立一个新的类Message,专门用来在两者间传递信息。

这三次作业的迭代基本上就是增加Message的信息含量和改变Elevator的运行模式。

2、可扩展性

第三次作业的可扩展性不好,一方面是电梯内部信息屏蔽,不改变设计的情况下必然受到限制。另一方面也是主要的一方面是我在电梯的运行方式上出了很严重的bug,导致电梯常常走到不存在的楼层,产生异常,根本原因是我在设计电梯运行方式时没有留下扩展的余地,在迭代过程中渐渐掌握不了代码的变化了,如果下一次迭代的话电梯运行的方式需要重写。

单一责任原则(SRP):

整体的架构基本满足单一责任原则,输入线程输入Request,电梯线程负责读取PersonRequest,但是存在部分问题:缓冲区同时担任控制电梯线程的工作,两者复合程度高。

开闭原则(OCP):

缓冲区的设计基本满足新增其他电梯不需要修改代码的需求,但是电梯需要修改代码才能添加新的功能。

可替换原则(LSP):

本次作业没有使用继承。

接口分离(ISP):

本次作业没有需要设置接口。

依赖反转原则(DIP):

每个类的功能层次均相同。

整体分析:

本次设计更加偏向于相同层次的类的协同,没有重视抽象与具体的层次结构,导致一些类在面向不同需求的时候需要部分重构。特别是第三次作业,由于没有下一次作业迭代,设计时也缺少从扩展性上考虑。

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

第一次作业:

类图

 

 

度量:

行数:

 

 复杂度:

时序图:

 

 

 

基本的生产者—消费者模式 

第二次作业:

类图:

 

 度量:

行数:

 

 复杂度:

 时序图

 

 

 修改了电梯的运行方式,为Building添加了控制电梯数量的功能。

第三次作业:

类图:

 

 度量:

行数:

 

 复杂度:

 时序图:

 

 

 电梯run方法这次过于复杂,导致了大量的bug出现,主要是把太多功能都交给run方法的缘故。 

4、分析自己程序的bug

第二次作业的bug是buffer内数据更新的问题,我用来标记那一层有人的信息在传递给电梯后自动清零。

第一、三次作业的bug都是电梯自己运转的问题,包括在满员的时候依旧向电梯里加人,往本来不存在的21层跑,在几个楼层之间反复徘徊就是停不下来等。都是因为我在写电梯的run方法时犯了错误,让电梯不能正确的维护自己的状态。

5、发现别人程序bug所采用的策略

使用python脚本随机生成输入信息,然后进行测试。

6、心得体会

我们在设计时要尽量留下修改的余地,在遵循现有的设计模式的同时,也不要过于死板。

posted @ 2020-04-16 09:14  日月久照  阅读(127)  评论(0编辑  收藏  举报