目录

  • 电梯作业的设计策略
  • 基于度量的程序结构分析
  • BUG分析及测试
  • 心得体会

电梯作业的设计策略

在整体的架构上,我三次作业使用的设计策略较为统一,主要的组成部件有:

  • 输入控制线程:用于控制输入,向主等待队列中添加请求(生产者)
  • 主控制线程:用于向电梯分发任务,从主等待队列中拿请求(消费者)
  • 主线程:主线程使用轮询的方式查看任务是否全部执行完毕,并结束程序
  • 电梯线程:用于运行每个电梯的等待队列中的请求
  • 主等待队列WaitList:一个线程安全的共享对象,设置putget方法来放入、拿走请求,并使用wait()notifyAll()来阻塞或唤醒访问该共享对象的线程

从具体的策略上讲,使用了生产者&消费者模型,输入控制线程和主控制线程构成一对生产者和消费者,二者的共享对象则是主等待队列WaitList,这里我们加锁来保证同一时间只能有一个线程访问该共享对象,通过wait()notify()来实现阻塞和唤醒访问该共享对象的线程;

主控制线程向电梯线程分配其执行的人员,每一个电梯具有自己的等待队列,而其任务就是循环执行分配到自己的等待队列中的任务,主控制线程和电梯线程之间的共享对象就是每个电梯的等待人员队列,这里我们同样加锁来保证同一时间只能有一个线程访问等待人员队列(共享对象);

  • 在单部电梯执行任务的策略上,我使用了LOOK方法,即电梯选定一个方向运送乘客,在执行完当前方向上的所有任务后,再更换方向执行后续任务;
  • 在人员分配策略上,我将能够直达的请求按照一定的规则分配给对应电梯进行处理,在这里需要考虑的问题是各个电梯的负载均衡和最终的时间最优。为了将各个因素综合考虑,在这里我设计了一种根据电梯和请求的当前状态进行“打分”的分配方式,即根据电梯是否已满电梯是否正在执行任务电梯目前所处楼层和方向和当前任务请求的匹配程度等几个指标来为每个电梯打分,最终将待分配请求加入得分最高的电梯中(但是由于测试不够&参数没调,导致运行的效果并不好)。对于不能直达的请求,则会先执行前一部分(运到中转层),由电梯线程放入大的等待队列,再由主控制线程进行新一轮的分配。在中转层的选择上,我结合了请求的运行方向分配电梯当前的运行方向请求发出的楼层进行了分配。
  • 程序结束的判定:输入线程终止且电梯运行完毕。
    在具体的判断上,当输入线程读取到null时,将一个信号量isEnd置位,主线程通过轮询+Sleep来判断以下条件:

    • 信号量isEnd置位
    • 主等待队列为空
    • 每个电梯处于空闲状态且每个电梯的等待队列、运行队列均为空

    在满足上述的三个条件的情况下结束程序

    但是,主线程可能在下述情况下出现错误的判定

    • 最后一个任务从主等待队列中取出,但还没有交给电梯的时候
    • 最后一个任务不能直达,从电梯中出来而未放入主等待队列的时候

    为了避免这样的情况下程序的提前截止,我让主线程在Sleep一小段时间后再次进行判断,只有两次判断均能满足的时候才会结束运行。

基于度量的程序结构分析

第五次作业:单部傻瓜电梯

  • 复杂度分析:

    本次作业中,Main由于需要监控各个线程的运行状况并结束程序,且具有一定的逻辑判断深度,所以造成了其OCavg指标复杂度较高;

而类Elevator由于需要维护其两个队列(运行队列和等待队列),并判断和执行相应的任务,单类中执行的功能较多,方法间的互相调用过于复杂,导致其WMC指标复杂度过高。

  • 类图:
  • 根据SOLID原则进行分析:
    • SRP:电梯类Elevator需要执行的功能较多,类内方法互相调用复杂,没有很好地满足单一职责原则;
    • OCP:由于电梯的调度策略改变,电梯和调度器均在后续进行了重写
    • 其他:本次作业中没有继承和接口,无抽象类

第六次作业:单部可捎带电梯

  • 复杂度分析:

    在本次作业中,同样是Elevator类设置的功能过多,导致其WMC复杂度较高,Main的逻辑判断深度及复杂度较高?。
  • 类图:本次作业的类图和第五次作业基本相同,不单独列出
  • 根据SOLID原则进行分析:
    • SRP:同第五次作业,电梯类Elevator需要执行的任务过多;
    • OCP:在本次作业中实现了单部电梯的LOOK算法,第七次多电梯作业中的不同属性和捎带策略的电梯是在继承本次电梯的基础上通过拓展实现的
    • 其他:本次作业中没有继承和抽象类

第七次作业:多部智能电梯

  • 复杂度分析:

    • Elevator执行功能过于复杂,Main依然逻辑复杂度很高(太懒了?)
    • Controller类需要监控各个电梯的运行状态,并根据不同的情况决定其运行策略,导致其逻辑判断的深度过高,在调试的过程中,这里也确实出现了很多BUG。
  • 类图:
  • UML时序图分析:
    三次作业的时序图基本类似,挑这次作业的画了一下

  • 根据SOLID原则进行分析:
    • SRP:Elevator需要实现的功能过多,没有很好地遵循单一职责原则;
    • OCP:Elevator实现基本的LOOK+捎带策略,ElevatorA/B/C通过继承父类Elevator来修改其各自可以停靠的楼层和不同的属性、捎带策略;
    • LSP:父类可以替换子类使用(但是调度策略不同);
    • 其他:本次作业中没有实现接口,无抽象类

BUG分析及测试

我的电梯在本阶段作业的公测和互测中没有出现BUG(也没有性能?),一方面是由于本模块的作业逻辑结构较为清晰,另一方面使用了一些极端样例和大量随机样例进行了测试。对于同组同学的程序,我也没有发现太多的问题。

在测试过程中,我使用了自动化测试来检测正确性,也用它来绘制电梯运行期间的时空图,以监测电梯的性能,统计了电梯的运行轨迹及负载(如下):

电梯运行时空图 图注:
蓝色:A电梯
绿色:B电梯
红色:C电梯
折线:电梯运行轨迹
每个方形的大小:当前电梯内人数

可以看出,在整个电梯运行的过程中,LOOK算法的执行情况较好。但是B电梯的负荷明显过高,而C电梯的任务量太少(运行时间短、运送任务少),电梯整体的运行图能够更加直观地展示在电梯生命周期内的运行负荷,也更易于找出任务分配的不均衡。

在互测阶段,我也为我们组另一位同学画出了这样的运行轨迹图,30S左右输入的40条左右请求,他的电梯运行了160S以上

从他的电梯运行图中我们也能发现,他的单部电梯在执行任务的过程中使用的算法不是非常合理,例如B电梯出现了大量”折返跑“的情况;多电梯的任务分配也存在问题,C电梯在程序运行期间有长时间”摸鱼“,A电梯亦有空等时间过长的情况。

心得体会

线程安全

  • 在设计时考虑到线程之间的同步互斥关系
  • 考虑不同线程和共享对象之间的关系
  • 合理上锁
  • 考虑所有情况,避免不安全的情况出现

设计原则

  • 首先保证线程安全
  • 在设计时充分考虑以后出现的情况,OCP原则
  • 设计清晰每个类的职责,遵循单一职责原则
  • 降低类之间的耦合度
  • 使用外部工具来进行正确性分析和性能评

转载于:https://www.cnblogs.com/lebway/p/elevator.html

面向对象的程序设计-模块二课程总结相关推荐

  1. Java 面向对象的程序设计(二)

    编写一个java程序,设计一个汽车类Vehicle,包含的属性有车轮的个数wheels和车重weight.小汽车类Car是Vehicle的子类,包含的属性有载人数loader.卡车类Truck是Car ...

  2. 像麦肯锡咨询师一样做商业分析_课程笔记 模块二:信息收集

    文章目录 模块二:信息收集 如何进行高效简洁的信息收集 数据信息的收集 常见的数据搜集渠道 上市公司年报和招股书--上市公司财务和经营信息最权威的来源 咨询公司研究报告--行业发展趋势研判.商业模式深 ...

  3. [Python3]Python面向对象的程序设计

    [Python3]Python面向对象的程序设计 一.面向对象的程序设计的由来 1.第一阶段:面向机器,1940年以前 最早的程序设计都是采用机器语言来编写的,直接使用二进制码来表示机器能够识别和执行 ...

  4. c#面向对象与程序设计第三版第三章例题代码_C#程序设计教程 | 教与学(教学大纲)...

    <C#程序设计教程>课程教学大纲 执笔人:xxx,xxx,xxx 编写日期:年 月 一.课程基本信息 1.课程名称:C#程序设计教程 2.课程编号: 3.课程体系/类别: 4.课程性质: ...

  5. Python学习之路9☞面向对象的程序设计

    Python学习之路9☞面向对象的程序设计 一 面向对象的程序设计的由来 见概述:http://www.cnblogs.com/linhaifeng/articles/6428835.html 二 什 ...

  6. python基础----面向对象的程序设计(五个阶段、对小白的忠告、关于OOP常用术语)、类、对象...

    一.面向对象的软件开发有如下几个阶段                                              1.面向对象分析(object oriented analysis ,O ...

  7. 【Python3之面向对象的程序设计】

    一.面向对象的程序设计的由来 1.第一阶段:面向机器,1940年以前 最早的程序设计都是采用机器语言来编写的,直接使用二进制码来表示机器能够识别和执行的指令和数据. 简单来说,就是直接编写 0 和 1 ...

  8. 第十篇 面向对象的程序设计

    第十篇 面向对象的程序设计 阅读目录 一 面向对象的程序设计的由来 二 什么是面向对象的程序设计及为什么要有它 三 类和对象 3.1 什么是对象,什么是类 3.2 类相关知识 3.3 对象相关知识 3 ...

  9. 十一丶面向对象的程序设计

    阅读目录 一 面向对象的程序设计的由来 二 什么是面向对象的程序设计及为什么要有它 三 类与对象 四 属性查找 五 绑定到对象的方法的特殊之处 六 对象之间的交互 七 练习 八 继承与派生 九 多态与 ...

最新文章

  1. 如果只能通过IE写博客【Do we write blog just only with IE?】
  2. 一文带你搞懂 MySQL 分区!
  3. GraphQL 初探—面向未来 API 及其生态圈
  4. 关于bat的变量赋值和解析机制
  5. 流程流转相关业务与流转的分离
  6. 红帽oracle关系,redhat和oracle linux kernel对应关系
  7. docker-compose安装问题
  8. [css] 使用css实现霓虹灯效果
  9. nginx管理面板_吸塑包装自建网站上线,阿里云ecs+bt面板+WordPress
  10. python ransac 拟合平面,PCL利用RANSAC自行拟合分割平面,
  11. Android——手机系统重装的备忘笔记
  12. Java对象序列化乱码6_对象序列化成字符串乱码解决
  13. 大学四年怎样过,做到这六点,甩别人一条街
  14. python罗盘时钟代码,罗盘时钟(原创)
  15. Linux自学:常用新建命令的使用方法
  16. 使用Simple Allow Copy插件在网页内复制文字
  17. 50个直击灵魂的问题_短不短,是一个直击灵魂的问题~
  18. 谈企业信息化项目经理培训
  19. elastic-job VS xxl-job
  20. 1068 万绿丛中一点红 (20分)

热门文章

  1. java类成员初始化_简单了解Java类成员初始化顺序
  2. linux内核之旅ppt_一起玩转 Linux 内核之旅开源社区吧
  3. 最小生成树之prim算法
  4. 赋能‘元宇宙’,这些企业强势破圈 | 2021AI 最佳成长榜
  5. Struts 2常见应用
  6. java object 详解_Java基础之Object类详解
  7. win10 远程桌面卡顿_Win10系统远程桌面连接缓慢卡顿解决措施
  8. python更改数据框指定位置的数据_python – 更改数据框中多个loc的最快方法
  9. 【k8s学习笔记】第二篇:在Ubuntu系统中安装kubelet,kubeadm和kubectl
  10. 跳跃问题(Java)