面向对象设计与构造2019 第二单元总结博客作业

作业回顾

  • 2.1 单部傻瓜式调度电梯设计
  • 2.2 单部捎带式电梯设计
  • 2.3 多部智能型电梯设计

一、三次作业的设计策略

  • 第一次作业只有正确性要求,没有性能要求,对于多线程的知识也没有过多涉及。所以我就无脑写了一个FAFS型,不含捎带的电梯。在正确性上有十分充足的保证,但是性能上很差劲,也没有什么可以说的策略。

  • 第二次作业加上了20分的性能分,但我并没有在性能上做出过多优化。我采用的策略是类似于磁盘扫描算法的LOOK算法,即模仿现实生活中电梯的算法。事实证明,这种调度策略在所有人的程序中并不算优秀。虽说我和其他部分人都是LOOK算法,但我在细节方面的实现非常粗糙,依然保留着上次作业的风格,并没有想尽可能多的去载人,而是尽可能让电梯路线不受牵制。这样,正确性虽好,但是性能分很低。
  • 第三次作业适当的扣除了性能分占比,让我们能更专注于正确性。我在写的时候,策略和第二次基本相同,所以正确性上没有很大问题。关于中转的问题上,我依然是选择牺牲性能来完善正确性。我将所有一部电梯无法送达的指令送到1层或15层(哪个近去哪),拆分成两条来处理。这样子正确性上有保证,但是效率依然不够。最后,我的性能分也并不理想。

    SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

二、基于度量的分析

1.时序图和类图

  • 时序图对于三次作业而言大同小异,多张图没有很大的参考价值,且占用空间。我在此放出第三次作业的时序图。可以看出,我采用的是生产者-消费者的模式,使用经典的生产者-消费者-容器三大类,对电梯运行进行有序处理。分发器采用notify的形式唤醒wait中的电梯,减少了CPU忙等待的时间。

面向对象设计与构造2019 第二单元总结博客作业 随笔 第1张

  • 三次作业的类图也是大同小异,我在此一并放出。

面向对象设计与构造2019 第二单元总结博客作业 随笔 第2张
面向对象设计与构造2019 第二单元总结博客作业 随笔 第3张
面向对象设计与构造2019 第二单元总结博客作业 随笔 第4张

  • 类图方面,可以看到类并不多,也没有建立过多类的必要。三次作业都以非常基本的设计模式构建。
  • 但是,就SOLID设计原则而言,我的程序做的并不够好。我的程序没有很高的复用性和广泛性,许多类的方法功能都写得比较死,是在面向对象的每个方法内尽情使用面向过程的思路进行编写。尤其是电梯的上下人开关门处理,一套过程性思路行云流水,却没有体现出对象之间的交互性。

2.经典度量数据

Type Name NOF NOPF NOM NOPM LOC WMC LCOM FANIN FANOUT
Elevator 7 0 6 2 63 9 0 1 1
Input 3 0 2 2 30 4 0 1 1
Main 0 0 1 1 11 1 -1 0 3
Switch 1 0 3 3 12 3 0 3 0
Type Name NOF NOPF NOM NOPM LOC WMC LCOM FANIN FANOUT
Elevator 11 0 16 2 223 57 0 2 2
Main 1 0 2 1 44 6 0 1 3
RequestList 3 0 5 5 25 6 0 2 0
Type Name NOF NOPF NOM NOPM LOC WMC LCOM FANIN FANOUT
Container 4 0 8 8 38 11 0.375 3 1
Dispatcher 4 0 7 2 91 17 0 2 3
Elevator 12 0 23 2 306 76 0 2 3
Request 3 0 5 5 24 5 0 3 0
TestMain 0 0 1 1 17 1 -1 0 3
  • 以上依次是我第一、第二、第三次作业的度量情况。可以看到,在代码行数(LOC)方面,电梯类Elevator一直是大头。三次作业中的电梯类代码行数占了总行数的50%以上,可以说将一切处理全部聚合在一个类中。这种设计并不算好的架构,但我本次作业又不知道如何去更好的拆分。
  • 第一次作业中,由于对生产者-消费者模型不熟悉,我甚至写了一个Switch类作为原子布尔型变量,作用是能够使得电梯线程停止工作。后面这种东西没有再出现。
  • 第三次作业中,程序的扇入扇出值较为合理,高扇入(FANIN),合理扇出(FANOUT),可以感觉到自己初步掌握了OO的设计诀窍。

三、分析自己程序的bug

  • 三次作业中,我为了追求正确性从而牺牲了许多性能,后果是三次作业中我都没有被检测出bug。课下我使用自己的测评机进行大量数据反复测试,得到的结果也十分稳定。所以在这里,我没有很多可以分享的内容。
  • 助教曾经提到过,输出类TimeableOutput不是线程安全的。但是我在实际编写程序的时候,无论锁不锁输出,对结果都没有影响。虽然我锁了,但是我依然没有弄清楚不锁可能带来的问题。

四、找别人bug的策略

  • 我坚信,越往后写,代码量越大,通过阅读他人代码的方式来找bug的行为会越发艰难。而且哪怕他人的代码有错,自己的思维也会非常容易被带入他人的错误写法中,从而导致一时间找不出错误。所以,我选择使用自动评测的方式,来寻找他人的bug。
  • 一台自动评测机器所需要的基本功能:
    • 随机数据生成功能
    • 编译运行、控制输入输出流的功能
    • 输出结果正确性判断功能
    • 判断结果可视化导出功能
  • 就这次的三次作业我自己写评测机的经验而言,难点在第二点,工程量大的重点在第三点。第二点是许多同学写出像样评测机的门槛,也就是定时输入的功能,给许多同学带来了困扰。这里我采用Python自带的subprocess模块来解决问题。此模块可以控制定时投放数据,也可以关闭输入流,非常方便。
  • 而输出结果的正确性判断,只是简单的逻辑问题。指导书中对于正确性判断说的十分清楚,我们只需要把助教的言语转化为代码就可以完成此功能,但是这个工程量未必比写一台电梯要小。所以大家可以量力而行。到第三次作业的时候我已经完全摸了,拿了第二次的程序改成三台电梯直接用了,没有实现特定楼层、超载判定等功能,有点可惜。

五、三次作业的心得体会

三次作业下来,我切实的体会到了OO思想和OO课程的特点。面向对象程序设计特有的设计模式,和多线程特有的设计模式,都超脱于之前学的所有知识,让我于困境之中发现了更多的惊喜。虽然电梯功能很简单,但是从其中学到的东西和面向对象的知识,远远超过之前的求导程序

多线程的学习中,线程安全很重要。线程安全的设计要点,在此之前的程序设计中从来没有涉及。对于临界资源的操作要谨慎再谨慎,是多线程有风险而有魅力的点。另外,wait()和notify()的使用要比忙等待更加节省资源,也是多线程设计中非常智能的设计功能。

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄