全文共2329字,推荐阅读时间10~15分钟。

文章共分四个部分:

作业分析

Unit2要求我们模拟现实生活中的电梯调度情景,迭代路径是单电梯->多电梯->特殊选层电梯。本单元的作业分析有独特的地方——因为三次作业都采用了一致的架构,因此以第三次作业的UML图为例即可了解整个单元迭代开发的过程。

从UML图可以很直接地看出来整个系统的模拟思路:通过分包策略,让输入(request)、分配(dispatcher)、调度(scheduler)、电梯本身(elevator)、时间控制单元(timeunit)之间实现“透明调度”。所谓“透明调度”和工厂模式有异曲同工之妙,只要保证包与包之间的调用接口不变,那么内部实现可以任意改变。也正是因为这个原因,三次作业的类图均遵循了上图的包模式。说完架构,下面分别分析三次作业的代码质量评估。

第一次作业

第一次作业要求我们实现一个可捎带的单电梯模拟系统。

UML图如下

  • 代码结构

结构可以大致分为三层,输入->调度->电梯运转,之所以把电梯运转单独拆出来,是因为电梯只有上下的功能,其他的带有判断逻辑的“自主意识”都在调度器中实现。

  • 复杂度分析


从反馈结果可以看出,由于把所有的判断逻辑都放进了调度器,造成了调度器的复杂度过高。在其他方法中,还是比较好的体现了“高内聚低耦合”的设计思想,均没有较高的复杂度。

第二次作业

第二次作业要求我们实现可稍带多电梯调度程序,并且能够自定义电梯数量。

UML图如下

  • 代码结构

代码架构基本延续了第一次的设计风格,虽然更换了调度策略,但是可以发现UML图的三层结构几乎没有变化。

  • 复杂度分析


从反馈结果可以看出,由于这一次的多电梯要求,我把请求的输入和分配都放在了输入层,导致复杂度相比于第一次有所上升。现在回看起来,输入逻辑和分配逻辑完全可以分开实现,这样就可以保证输入类的“单责性”。

第三次作业

第三次作业要求我们实现可稍带的特殊电梯调度,并且可以动态改变电梯的数量。

UML图如下

  • 代码结构

代码架构基本延续了第一次的设计风格,在输入层增加了Dispatcher来实现分配逻辑。

  • 复杂度分析


从反馈结果可以看到,由于Dispatcher的出现,原本复杂度很高的输入调度层都有所改变,但是由于分配策略过于复杂,导致Dispatcher的复杂度变得很高,可以考虑再次切分分配策略:比如将一部分状态分析的方法放进调度器中直接实现一个反馈接口交给分派器。

SOLID Principle

  • S:单一功能原则
  • O:开闭原则
  • L:里氏替换原则
  • I:接口隔离原则
  • D:依赖反转原则

逐一分析,单一功能原则在每一次的迭代中都有不同程度的提升,比如InputDispatcher的分离;开闭原则体现得比较明显,因为更新调度器时除非采用不同的线程管理方式,其余部分都不用更改;里氏替换原则在本单元中不好展现,毕竟都没有继承关系。;接口隔离原则在一定程度上有助于实现前面提到的开闭原则;依赖反转原则是本单元让我体会最深刻的原则之一,因为先写上层架构,同时为下层留好待实现接口的方式,可以在开发过程中合并很多不必要的方法或者变量,同时更能够体现层次化思想。(感觉有点像先写评测机再做开发)

时序图(Sequence Diagram)

评测相关

详情见这里(https://www.cnblogs.com/silencejiang/p/12701979.html)

重难点聚焦

从三次开发和互测的过程来看,问题主要都在CPU时间上。这个问题之所以能够获得如此“殊荣”,主要是以下两个原因:

  • 本地测试CPU时间(啥玩意儿?)
  • 不只polling会导致过高的CPU时间,就算用wait-notify,要是没操作好,结果是一样的。

对于第一点,在和大家的交流以及经过了学长的指点后,发现这个问题对win用户确实很不友好——在linux下使用time系统调用可以轻松地实现上述操作。但是,我们有万能的python——在time库中有一个神奇的函数process_time(),根据官方文档是可以实现和前者一样的功能的。但是,由于这个函数的subprocess的兼容性并不好,最后还是选择了前者。(I am so into Linux)

对于第二点,因为最开始设计的结束方式是在程序结尾统一notifyAll(),这样会导致程序和polling无异,CPU时间过高也就出现了。

Hack所用的策略

主要有两种方式:

  • 使用完成作业时有意义的样例进行测试
  • 利用评测机自己生成数据

评测机简要介绍

这是评测机的working directory

  • center:存放评测的核心控制代码,用于组织编译->运行->反馈功能

  • data:存放自动生成的数据

  • download_data:存放测试中出现问题的数据,可以用于回归测试。

  • factory:存放数据生成代码

  • output:存放各个测试代码的输出

  • result:存放各个测试代码的结果

  • ruler:存放标程

  • src:存放源码

  • filter.py:用于格式化数据以提交

本单元的评测机延续了上一单元的架构,但是加入了多线程评测和JAR包评测机制。原因很简单,多线程可以提高评测的速度,JAR包评测可以提高对不同架构程序评测的兼容性。

值得一提的是,本次加入了运行结果的可视化分析,分别是:

  • 运行时间走势

  • 在所有数据里取得最优解的次数

  • 平均调度时间及其方差和标准差(标准差在该情境下和方差等价)

通过可视化分析,我逐渐明白一个道理:生活中的最优解用大数据的思想来探寻,比起挠头冥想会不会更轻松一点呢?

重构策略

在三次作业的完成过程中,我都是先确定好架构再开始完成的,所以没有遇到需要从头开始重构的情况。

但是值得一提的是,由于优化需求,每次都利用了上文提到的可视化思路进行策略的选择,因此调度策略在三次作业中都有或多或少的改变。同时,接口一致性保证了除了调度器之外的部分不需要进行逻辑上、架构上的修改。

课程体验感受

这一单元的迭代开发让我初步接触了现代软件开发的基本功:多线程。

总的来说体验良好,这种让计算机硬件发挥它最大作用的感觉非常棒。同时,也让我开始重新审视那些我自以为已经拿在手上的工具,比如Python.以前从来没有使用过Python的多线程模块,这次为了开发评测机就小有涉及;之前和matplotlib只是点头之交,现在逐渐觉得自己还要领会的东西真是数不胜数,期待未来的路上还会出现的小确幸吧。

最后一定要说的是:谢谢讨论区里的老师、助教、同学,是大家让我真正领会了一句很久以前看见的话:

一个人可以走得很快,但一群人才能走得更远。

Unit2-窝窝牌电梯的更多相关文章

  1. OO_Unit2 多线程电梯总结

    OO_Unit2 多线程电梯总结 相比于Unit1的表达式求导,Unit2的多线程电梯听上去似乎显得更加"高大上".但在完成了3个task的迭代后再回过头去比较这两个单元,我发现其 ...

  2. BUAA_OO_第四单元

    一.UML解析器设计 ​ 先看下题目:第四单元实现一个基于JDK 8带有效性检查的UML(Unified Modeling Language)类图,顺序图,状态图分析器 MyUmlInteractio ...

  3. OO Unit2多线程电梯总结博客

    OO Unit2多线程电梯总结博客 传说中的电梯居然就这样写完了-撒花

  4. 电梯系列——OO Unit2分析和总结

    一.摘要 本文是BUAA OO课程Unit2在课程讲授.三次作业完成.自测和互测时发现的问题,以及倾听别人的思路分享所引起个人的一些思考的总结性博客.主要包含设计策略.代码度量.BUG测试和心得体会等 ...

  5. OO Unit 2 电梯调度

    目录 OO Unit2 博客作业 基于度量来分析⾃己的程序结构 复杂度分析 架构分析 改进和重构 发现过的BUG 简化问题 多线程初探 OO Unit2 博客作业 基于度量来分析⾃己的程序结构 自认为 ...

  6. 面试题:电梯/雨伞/杯子/笔/A4纸/纸杯… 怎么测试?

    目的 面试的时候,面试官出题可能会出其不意: 比如随意指定生活当中的一件物品,问你如何测试,见下 作为测试人员,电梯/雨伞/杯子/笔/A4纸/纸杯… 怎么测试? 面试官的考察点 1.在没有需求文档或者 ...

  7. OO Unit2 总结

    OO Unit2 总结 OO课Unit2电梯仿真项目技术回顾 BUAA.1823.邓新宇 2020/4/17 Part1 设计策略 从多线程的协同和同步控制方面,分析和总结自己三次作业的设计策略 第一 ...

  8. OO unit2 summary

    Unit2 一.第一次作业 1.UML 2.Sequence Diagram 3.同步块设置与锁处理 采用了生产者-消费者模式,用共享对象来连接不同的线程. 第一次作业中,我有三个线程:Receive ...

  9. c 算牌器代码

    int main() { // 算牌器 ]; ; do { printf("请输入牌名: \n"); scanf("%2s",char_name); ; ]) ...

随机推荐

  1. System.Web.mail ----虚拟发件人发送邮件

     转载别人的 使用SMTP发送邮件   说到邮件发送,先提一下SMTP. SMTP的全称是“Simple Mail Transfer Protocol”,即简单邮件传输协议.它是一组用于从源地址到目的 ...

  2. LaunchScreen作为启动图设置,修改无效的解决方案

    原有的推流APP用launchScreen做的启动图,现在要修改一张,发现修改无效. 当前测试的方法有 1,重启Xcode  卸载app 清楚xcode缓存 2,修改launchScreen.stor ...

  3. Socket - TCP编程

    Socket是网络编程的一个抽象概念. 通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可 socket参数及常用功能 ...

  4. web项目——启动时tomcat报错:Server Tomcat v7.0 Server at localhost failed to start.

    报错信息:Server Tomcat v7.0 Server at localhost failed to start. 报错截图: 原因分析:在使用SSM框架时,生成的mapping与系统配置文件不 ...

  5. WordPress批量更换域名

    UPDATE wp_options SET option_value = replace( option_value, 'http://www.old.com', 'http://www.new.co ...

  6. Linux操作系统分析 | 深入理解系统调用

    实验要求 1.找一个系统调用,系统调用号为学号最后2位相同的系统调用 2.通过汇编指令触发该系统调用 3.通过gdb跟踪该系统调用的内核处理过程 4.重点阅读分析系统调用入口的保存现场.恢复现场和系统 ...

  7. burpsuite 2.0beta体验

    这里有破解版:http://ximcx.cn/post-110.html 一直再用1.7x版本,2.0的还没怎么用过 移除了 Scanner 和spider 选项卡,全部整理到Dashboard里 代 ...

  8. 多用户vps管理面板怎么安装,有没有好用的vps管理工具

    一.VPS安装VPSMate控制面板步骤 1.使用SSH连接到VPS.使用命令获取VPSMate安装包: wget   http://www.vpsmate.org/tools/install.py ...

  9. 关于替换“c2a0”十六进制字符的方法

    一.背景:在爬取网络小说生成的文件中,发现有些空格没法替换,使用十六进制编辑器查看,发现这些空格字符的十六进制值是“c2a0”,其来源是网页控制的特殊字符,这是一个叫做Non-breaking spa ...

  10. SpringMVC(二)返回值设置、数据在域中的保存与SpringMVC案例

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.返回值的设置 1.返回 String [1]返回 String 默认情况 @RequestMappi ...