ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

我永远爱着OOP——第二单元作业总结

2019-04-20 12:50:59  阅读:222  来源: 互联网

标签:调度 Commander 爱着 电梯 指令 OOP 测试 设计 单元


第二单元的电梯真是愉♂快呢,多线程编程作为java编程OOP中的重要组成部分,通过这一个单元的学习,我也是有了很多全新的认识

那么下面就先例行一下公事


三次作业分析

第五次作业

设计分析

实现的电梯是很简单的,没有复杂的逻辑,主要目的应该也是帮助同学们入手多线程编程,加上课上对设计模式有所点拨,所以整体的设计应该是不难的,编码量也不大,只要处理好锁的关系和waitnotify的时机,不要出现死锁,基本是不会有什么问题的

下面给出我的设计,也就是中规中矩的生产者-消费者模式

这里我封装了自己的一个容器Requester(感觉什么东西加上个"者"后缀就很厉害呢),其实就是一个请求队列,实现了一下迭代器接口(后来发现不好用

然后就是电梯线程和电梯线程,调度器线程没有启用,这个设计主要是为以后的扩展做了一点准备,所以这里的Scheduler是个静态的

然后差不多就是这样了,邻接资源就是那个队列,使用的时候锁一下就好了

一个需要注意的地方是怎么控制输入结束的全局持续通知

这里是借用了信号量的思想,也就是设置了一个相应的属性,然后每次循环的时候查看一下这个信号,别的就没什么了

下面是整个程序的一些度量(忽略这只手)

因为有各种各样的输出语句,所以Elevator类的方法好像有点多了,不过我确定一定很短,很简单

你看

方法的复杂度都很低,看起来还是可以的

测试

对于多线程的程序我不是很清楚怎么做单元测试,单元测试也只能保证模块功能正常,但是我们都知道,真正的问题往往出现在线程的控制上的。

分享课上同学们分享的也都是各种黑盒测试(个人是比较鄙弃全部依靠黑盒测试的行为,盲目的随机胡测也许很有效,但是绝不优雅),所以也欢迎大家分享如何富有逻辑地进行测试。

第六次作业

第六次加上了捎带规则,加了点楼层,加了负层,0层神秘消失(误),整体来说笔者的设计是这样的。

三次设计的思路都是坚持做到单一职责,毕竟分割职责可以在做修改和扩展的时候放心大胆(我一向很大胆,其实是因为分隔职责后便于测试,良好的测试是修改的保险丝)。

所以就是

  • 输入线程只管输入,是一个无情的指令接收机器
  • 电梯线程只管执行,是一个无情的指令执行机器
  • 调度线程负责调度,完成(无情地)指令分发的任务

然后这样的设计就出现了

!

相比上次的设计,没太多变化,就是调度器动起来了,然后肩负起分配指令的任务

然后电梯中需要有一个队列维护自己持有的指令,线程变成了单步执行,每层看一看有没有上下开关门事件发生,逻辑不算复杂

调度器就是不断尝试将指令放入电梯中(后来笔者发现这里设计的不好,调度器空转太多了,加一个waitnotify机制会更好,或者是join,不过想来想去,抢占式或许是最优解,这个后面再说)

然后下面是整个程序的度量

可以看到调度器的复杂度比较高,其实主要是笔者作死的一个设计

笔者为指令和电梯运行加了一个方向的概念,因此自己给自己多设置了一层逻辑,没什么意义,也就是有MainRequestDirection两个量都表征运行方向,每次更新都要更新俩,判断的时候用哪个也说不清,确实是很糟糕的设计,笔者在后面也把这个量给废弃了

测试

关于这次的测试,笔者给出一些个人思考的可能出现问题的情况

  • 对于LOOK玩家,在电梯折返,或者说换向的时候打断,可能是一个边缘逻辑
  • 对于开关门和来指令的并发情况
  • 对于错过的指令的测试

第七次作业

设计分析

据说这是OOP作业难度的顶峰

鬼畜多电梯、负载、速度、随机突发随机指令,这几个情境下设计一个好的算法确实不容易

所以与其苦心分析设计,不如"实践检验真理",也就是通过本地测试时间来决定算法的性能(真是个小机灵鬼

所以在说我的设计之前,我想理性(瞎胡说)地分析一下这次调度算法的考虑

1. 关于接人和方向

(笔者很讨厌上楼的人在电梯下行的时候就上电梯),在本次作业中,出于载荷的考虑,也是加上同向捎带的判断,电梯的性能应该会好一些,但是实际检验发现,这个判断的效果并不明显,并且有的时候会出现负优化,个人分析原因是在于40条指令,三个电梯的总容量有20多,所以即使面对40指令并发,对于电梯们来说,工作量也不是很大。

正因如此,像我们考虑的情景——“很多反向请求的人上电梯,导致同向的请求上不去”,其实发生率也不高,所以在这种情景下,大吞吐反而是很优的。

2. 细节优化

对于这个评测方式,其实很多细节优化的效果也是不错的(只指分数,不保证绝对时间差),比如电梯的选择顺序,是快的优先还是随便来;是近的优先还是随便来。这种细节上的选择也会有不错的收益。

3. 抢占式很重要

如果让调度器主动分指令,电梯就要记着一会要接谁,即使这个人不在电梯里,出于安全考虑,电梯也必须为这个人留个位置,那么在这种情景下,电梯一般是一直装不满的。

本人的算法基本是硬调度,没有动态调度,调度规则都是硬编码的。(不像那些大佬们在电梯运行的时候动态通信)

程序的逻辑就是每次楼层改变和进出人后就去中间的Commander那里pull一下,看看有没有自己能拿走的,这样可以保证最大利用电梯容量

然后pull的逻辑是在Commander中实现的,Commander获取电梯的当前状态,然后判断队列中有没有他能拿走的

下面是程序的度量

看起来Commander好像不太高兴了,因为笔者不小心把指令分割的逻辑放到了Commander里面,这个是违反单一职责原则的,我在下面简单做一下拆分

可以看到,加上Spliter后,Commander的复杂度明显下降,此时Commander中只剩下和分配有关的逻辑

方法的复杂度还是很不错的

测试

这次测试笔者主要关注了下面这几个点:

  • 载荷,要保证不能超载,对于电梯载荷上限的数据要进行测试
  • 需要拆分的指令,对于需要拆分的指令,特别是可以多次拆分的指令,要重点测试
  • 效率,最好在测试的时候单步输出一下每时刻每座电梯中的人数,确保电梯有较高的载重

好了,我完事了

上面就是本系列作业的设计了,下面说一些我想说的

相比于上个系列作业,这个系列突出的需求增加更加明显,也更加友好,不存在说两次需求相互矛盾的情况,对于设计优秀的同学,每次作业的编码量肯定是不大的

然后吧,这个时间效率这个事情,我觉得确实是一个摸索的过程,群里有人在说用NN,问题不大,其实我上面说到的自己去尝试算法,然后调整算法,其实就是个手动NN的过程(误),真正要是在实际中解决这种鬼畜电梯的问题,就是要靠NN来实现根据过去推将来的,用NN来实现对未来的分析预测,从而调整自身调度策略,获得最优调度

下面想重点说一下这个监听者模式,老师上课提了很多次,下课也听同学们有讨论,所以说一点个人的见解(以下都是胡说,理性参考)

监听者模式的提出,是为了能够让一个个的listener动态地加入监听和退出监听,同时,在Commander新消息发布的时候,可以通知所有监听者,javaSwing库就大量使用了这种设计

针对本次作业,笔者最开始是考虑过用这个模式的,每当输入一个指令就通知一下电梯,然后电梯取指令,刚好很多电梯,然后可以都注册为listener

但是存在以下几个问题:

  • 所谓通知,在这里的体现就是把指令放进去,但是,在指令来的时候,电梯可能正处于上锁状态(例如,进出处理中),这时我们的Commander试图尝试往每个电梯里放指令,就会遇到锁
  • 其实上面那个还不是最重要的,毕竟只是要等一下下就好,问题是当某个请求无法被任何电梯处理的时候,这个请求就要被存起来,这样的话,其实就又退回了我们的生产消费模型了(毕竟在Swing中,如果一个消息没有监听器,这个消息是会被扔掉的,但是显然我们这里不能这样)

所以,这个模式虽然很美,但是放在本系列作业中也许有些不当之处,当然,这只是我浅薄的认识,如果大家有更好的实现方式,也欢迎在下面留言,一起讨论,一起学习

标签:调度,Commander,爱着,电梯,指令,OOP,测试,设计,单元
来源: https://www.cnblogs.com/Nocturne/p/10740559.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有