全文共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. Jquery学习2---倒计时

    以下代码是mvc4.0代码,其功能是让页面上的数字3,变2,变1 然后跳转页面 @{ ViewBag.Title = "LoginOut"; } <html> < ...

  2. Java Web之路一:过滤器(Filter)

    一.过滤器(Filter)简介 过滤器是对web资源进行拦截,做一些处理后再交给下一个过滤器或Servlet处理,主要可以拦截request和response 过滤器是以一种组件的形式与web程序绑定 ...

  3. Redis设计原理简介

    学完MySQL InnoDB之后,又开始学习和研究Redis. 首先介绍下书:<Redis设计与实现>第二版 黄健宏著,机械工业出版社,388页,基于redis3.0版本.版本有点低,这个 ...

  4. 苏浪浪 201771010120 《面向对象程序设计(java)》第七章学习总结

    第七周 1.实验目的与要求 (1)进一步理解4个成员访问权限修饰符的用途: (2)掌握Object类的常用API用法: (3)掌握ArrayList类用法与常用API: (4)掌握枚举类使用方法: ( ...

  5. mac OS和win7笔记本实现文件共享

    记录下macbook通过共享读取win7笔记本中文件的过程,条件是两台电脑处于同一无线网中 win7操作 点击网络图标--属性--更改高级共享设置 选择公用后选择以下选项:启动网络发现--启动文件和打 ...

  6. LightOJ1282

    题目大意: 给出 n 和 k,请你求出 n^k 次方的前三位和后三位. 解题思路: 后三位用快速幂,不加赘述. 求前三位的方法: AC代码: #include <iostream> #in ...

  7. python 生成随机字符串

    1.生成随机字符串 #数字+字母+符号 def getRandChar(n): l = [] #sample = '0123456789abcdefghijklmnopqrstuvwxyz!@#$%^ ...

  8. [PHP学习教程 - 网络]004.模拟发送HTTP请求[GET/POST](HTTP Simulator)

    引言:经常在开发期间,客户端与服务端的调试都是借助于真实的容器返回.尤其是在处理到POST时,通常刚刚入门的兄弟姐妹就一定要借助容器.今天,我们就来处理一下模拟HTTP. 本文列举了常见的四种请求方式 ...

  9. [翔哥高手无敌之路]0-002.如何提取apk中的信息?

    面对一款apk软件,我们如何去获取它的信息,如何获取它的版本号,包名,或者ID,用户权限,这些信息都隐藏在apk包中的AndroidManifest.xml文件中,解开它我们就能获取任何想要的信息.但 ...

  10. Rocket - tilelink - Fuzzer

    https://mp.weixin.qq.com/s/hAKpZHy0IU6_XEvctfkHOA   简单介绍Fuzzer的实现.   ​​   1. IDMapGenerator   功能类似于I ...