全文共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. [Asp.Net Core] Blazor Server Side 扩展用途 - 配合CEF来制作带浏览器核心的客户端软件 (二) 可运行版本

    前言 大概3个星期之前立项, 要做一个 CEF+Blazor+WinForms 三合一到同一个进程的客户端模板. 这个东西在五一的时候做出了原型, 然后慢慢修正, 在5天之前就上传到github了. ...

  2. 解决CentOS无法识别网卡问题

    在联想电脑安装CentOS 6.9系统的时候,出现了无法上网问题,记录下这一路的坑. CentOS安装时在设置主机名这一步的下方有配置网络按钮,而此时该按钮点击无效.进入系统后发现没有网络连接. 在终 ...

  3. POJ2758 Checking the Text

    题目链接:https://vjudge.net/problem/POJ-2758 题目大意: 先给出一串原始字符串,在此基础上执行两种操作: 1.在第 p 个字符前添加字符 ch,如果 p 比现字符串 ...

  4. 基于 abp vNext 和 .NET Core 开发博客项目 - 异常处理和日志记录

    在开始之前,我们实现一个之前的遗留问题,这个问题是有人在GitHub Issues(https://github.com/Meowv/Blog/issues/8)上提出来的,就是当我们对Swagger ...

  5. Maven快速入门(一)Maven介绍及环境搭建

    做开发的程序员都知道,在系统开发需要各自各样的框架.工具.其中有一种工具不管你是初级程序员还是高级程序员都必须熟练掌握的,那就是项目管理工具(maven.ant.gradle).接下来就总结Maven ...

  6. Java中的集合(七)双列集合顶层接口------Map接口架构

    Java中的集合(七)双列集合顶层接口------Map接口 一.Map接口的简介 通过List接口,我们知道List接口下的集合是单列集合,数据存储是单列的结构.Map接口下是一个键值对(key-v ...

  7. JAVA中的注释方法

    Java的三种注释方法 ①单行注释:使用 // ,其注释内容从//开始到本行结束,比较常用, 快捷键为:Ctrl + / 或者  Ctrl + Shift + C  取消注释:Ctrl + / 或者  ...

  8. 公司如何通过电脑监控来规范员工行为-iis7服务器管理功能教程

    现在员工办公基本都用电脑,而电脑不仅仅可以用来处理工作,还可以上网.娱乐等.往往很多员工的自制能力比较差,在工作时间和人聊天,浏览购物网站,看新闻,炒股等休闲娱乐上花费大量的时间,导致工作效率降低,影 ...

  9. Golang基础教程——map使用篇

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是golang专题的第7篇文章,我们来聊聊golang当中map的用法. map这个数据结构我们经常使用,存储的是key-value的键 ...

  10. JAVASE(七)面向对象:封装性(特性之一)、构造器、属性、关键字

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.封装性 1.为什么要使用封装性? 创建对象以后,可以通过对象.属性名的方法进行赋值.只能限制数据的类 ...