OO第二次博客作业—17373247
OO第二次博客作业
零、写在前面
OO第二单元宣告结束,在这个单元里自己算是真正对面向对象编程产生了比较深刻的理解,也认识到了一个合理的架构为编程带来的极大的便利。
(挂三次评测分数 看出得分接近等差数列 菜鸡本质暴露无遗)
一、总体设计策略
三次作业设计策略基本相同。前两次是四个类:Main、Elevator、Taker、Waiter;两个线程:main、elevator。第三次在此基础上多了一个类:Dispatcher,一个线程:dispatcher。之所以前两次没有调度器类,是因为由于只有一个电梯所以直接把调度器安在这个电梯内部了。其实算一种偷懒行为。
基本算法是若Taker队列为空,电梯从Waiter队列中取一个主请求,将其送到目的层,然后在途中实现捎带(可以进也可以出);然后送达后若Taker队列非空,则从其中选一个Taker作为新的主请求。调度器的功能是为电梯分配相应的Waiter队列。
由于架构合理,三次作业没有出现重构现象。
本来想在第三次作业的调度器类采用单例模式,但是实现上出现了一些问题,于是没有采用(后来证明并不是单例模式的问题,而是线程安全的问题,最基本的ArrayList线程不安全,自己属实智障了)
二、基于度量的分析
第一次作业
总体结构分析
第一次作业由于是首次接触多线程编程,事实上最初还是遇到了一些语法上的困难的;但是解决了基本的语法问题之后,剩下的算法问题就轻而易举了。(据说第一次100分遍地都是)
但是幸运的是自己在第一次作业便打好了合理的架构,便使得之后两次作业只需要添添补补就可以轻松实现,让自己在这个单元没有尝到重构的滋味。
基本架构:将Request分为Taker和Waiter两类,其中Waiter类要增加一个toTaker方法,其余基本完全对称。而在电梯内部也几乎是完全对称,基本原因就是只有Waiter才能进,只有Taker才能出。但是采用了轮询。
存疑:采用了线程安全的阻塞队列(BlockingQueue),然而相关知识并不十分完备,所以只用了一些最基本的方法(比如poll),还有很多可以深入学习。
复杂度分析
可以看出基本没有红字,这也是我所说的架构合理的一部分。Elevator类里方法过多也是没有办法的事情,因为自己觉得这个实现也非常自然了,实现可能啰嗦一些但是思路是绝对简单清晰的(而且第一次已经实现了捎带)。
第二次作业
总体结构分析
从来没有比第二次作业更轻松的一次了;因为捎带这个事情上一周就写好了,只要稍微改一改数值(而且中测1次AC)。除此之外处理了轮询问题。但是捎带的算法肯定比较low了,因为只有92分的强测成绩。
复杂度分析
可以看出基本上和第一次无甚出入。
第三次作业
总体结构分析
第三次作业终于不能再偷懒了;终于加入了调度器线程。加入调度器线程之后线程交互性大大增加,这也使得这次作业和之前两次出入巨大。但是幸运的是Elevator类基本还是那个Elevator类,也就是说电梯该怎么跑还是怎么跑,接人捎带人都还是电梯的事情,调度器只是为了分配给电梯相应的乘客而已。也算是大大减小了第三次作业的设计难度。但是优化实在是基本形同虚设,还是自己太菜了,性能分基本为零。
复杂度分析
可以看出调度器的加入导致复杂度大大增加,这也是总体结构分析中说的一部分。
SOLID原则
SOLID原则指:单一责任原则、开放封闭原则、里氏替换原则、依赖倒置原则、接口分离原则。
单一责任原则:每个类只负责自己的事情。自己认为做的还不错,挑毛病的话可以是前两次没有调度器,或者说调度器在电梯里。但是单电梯的话,也就没必要去分配乘客,所以是完全可行的。第三次中,调度器只负责分配乘客,电梯只负责运行。
开放封闭原则:软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。三次作业可扩展性很强,事实上,不用重构而只需要修改参数就说明了这一点。而封闭可以将电梯上下行、接送乘客设计为抽象方法,但是本次作业不必要这样做。
里氏替换原则:派生的子类应该是可替换基类的。继承Thread类是唯一的继承,这和设计层面的继承是两个概念。
依赖倒置原则:高层模块不应该依赖低层模块,相反,他们应该依赖抽象类或者接口。也就是强调高层模块的抽象。本次根本不涉及什么高层模块,也就不用管。
接口分离原则:类不应该被迫依赖他们不使用的方法,也就是说一个接口应该拥有尽可能少的行为,它是精简的,也是单一的。三次作业根本没有用接口,就连Thread类也是继承,没有去实现对于Runnable的接口。
三、bug分析和互测策略
bug分析
三次作业没有出现强测的WA点,所以只谈一下编程过程中、最后一次提交前遇到的问题。
其实最主要的还是线程安全问题……这个问题贯穿于三次作业中,主要是,这个问题可能很不起眼,但是却很致命(说的就是你,一个小小的ArrayList不安全花了一个晚上的时间来debug)。而且多线程调试的问题实在是与之前的程序差别太大了,所以尝试了很多调试方法,然后到头来得到了一个真理:printf大法好!(滑稽)
互测策略
互测说实在的,根本没有针对性。屋子里也是要么一片宁静祥和,要么大家象征性地空刀几下。但是互测也不是没有它存在的意义,自己就是在互测中膜了某位巨巨的代码增进了自己对于单例模式的理解(虽然后来没有成功运用到自己的代码之中,但是自己确实深刻感受到这个是好东西啊)。
总的说来,三次作业没有强测bug,没有互测bug,不用bug修复,除了性能分不是太好看之外,属实惬意许多(想起了自己第三次求导bug修复了一天,那种滋味真的酸爽)。
四、心得体会
第一,一定要重视合理架构!尤其是在第一次作业之中。因为第一次作业是最简单的,所以在解决语法问题之后算法问题就轻而易举,那剩下的时间干啥呢,偷懒吗。。或者说,从最开始就思考问题对象最本质的特征,按特征分配类和对象。一个合理的架构会为之后的二、三次作业带来极大的便利。重构一时爽,话是这么说,但相信没人想每次都从头再来吧?
第二,一定要重视线程安全!多线程与单线程编程最大的区别、也是最大的差异就是线程数量的增加(这不是废话么),但也正是因为这是最主要的区别,所以它带来的线程安全bug也就是最大的差异,而别的bug基本都是之前的那种bug了,因此那就无需多提。
五、写在后面
三次作业虽然没有WA点,但是调度算法并没有找到一个太满意的算法。第二次也就是单电梯简单,所以直接类似SCAN算法完事,得分也还不错,估摸着进A组了;第三次轮到多电梯,依旧是SCAN算法就不大好使了,原因就是没找到一个好的分配等待队列的算法,结果就是强测性能分基本为零咯。
抛开分数不谈,通过了这三次电梯作业才真正让自己对面向对象编程思维有了较为深刻的理解,从中稍微窥得OO的本质,也算是自己的很大的一个进步了吧。
OO第二次博客作业—17373247的更多相关文章
- OO第二次博客作业——电梯调度
OO第二次博客作业——电梯调度 前言 最近三周,OO课程进入多线程学习阶段,主要通过三次电梯调度作业来学习.从单部电梯的傻瓜式调度到有性能要求的调度到多部电梯的调度,难度逐渐提升,对同学们的要求逐渐变 ...
- OO第二次博客作业(第二单元总结)
在我开始写这次博客作业的时候,窗外响起了希望之花,由此联想到乘坐自己写的电梯FROM-3-TO--1下楼洗澡,然后······ 开个玩笑,这么辣鸡的电梯肯定不会投入实际使用的,何况只是一次作业.还是从 ...
- oo第二次博客作业
多线程协同与同步控制总结 第五次作业-多线程电梯 本次作业是我第一次接触多线程,建立了请求模拟器.调度器和电梯运行三种线程.请求模拟器负责在输入后识别有效请求:调度器在扫描有效请求后将新的请求加入请求 ...
- OO第二次博客作业--第二单元总结
第一次作业 1. 设计策略 第一次作业,一共三个线程,主线程.输入线程和电梯线程,有一个共享对象--调度器(队列). 调度的策略大多集中到了电梯里,调度器反而只剩下一个队列. 2. 基于度量的分析 类 ...
- [BUAA OO]第二次博客作业
第五次作业 这次作业是电梯系列作业的终极版,要求是使用多线程实现三部电梯的运行.这次作业的难点在于第一次运用多线程技术,对于线程中的行为并不了解,以及电梯功能的实现(如果之前作业采取的是扫描指令队列预 ...
- Java第二次博客作业
Java第二次博客作业 时间过的很快啊,在不知不觉中这门课程的学习也就快要过去一半了,现在就来总结一下在这个第二个月的学习当中存在的问题以及得到的心得. 1.前言 第四次题目集和第五次题目集给我的感觉 ...
- 第二周博客作业 <西北师范大学| 周安伟>
一,本周助教小结 逐步开始适应助教工作,对学生发布的博客进行点评,查看学生对软件工程前期的准备情况. 二,助教本人博客 https://home.cnblogs.com/u/zaw-315/ 三,学生 ...
- C语言第二次博客作业---分支结构
一,PTA实验作业 题目1.计算分段函数 本题目要求计算下列分段函数f(x)的值: 1.实验代码 double x,result; scanf("%lf",&x); if( ...
- C语言第二次博客作业——分支结构
一.PTA实验作业 题目1:计算分段函数 1.实验代码 #include<stdio.h> #include<math.h> int main(void) { double x ...
随机推荐
- php 常用正则
1 手机 /^1[34578]\d{9}$/2 qq /^[1-9][0-9]{5,10}$/3 邮箱 /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za ...
- 网络编程之socketserver以及socket更多方法
关于socketserver 关于socket的更多方法 服务端套接字函数: s.bind() 绑定(主机,端口号)到套接字 s.listen() 开始tcp监听 s.accept () 被动接受tc ...
- VS2017 未找到编译器可执行文件 csc.exe
vs2017 网站报错 原因Web.config是中下面这段:注释就可以了 <!--<system.codedom> <compilers> <compiler l ...
- BZOJ 1053 - 反素数ant - [数论+DFS][HAOI2007]
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1053 题解: 可以证明,$1 \sim N$ 中最大的反质数,就是 $1 \sim N$ ...
- 更为复杂C程序的运行时结构
运行环境 win 10 企业版 1809 17763.194,MinGW V3.14 32位,Bundled V3.13.2,Bundled GDB V8.2. 在C语言中,栈的方向是从高地址向低地址 ...
- 使用OMS查询Api Management的调用日志
打开Azure portal,找到要操作的Api Management 实例,点击菜单Monitoring/Logs Schema Tab页搜索"diagnostics",选中Lo ...
- 洛谷P4051 字符加密 [JSOI2007] SA
正解:SA 解题报告: 传送门! 和工艺那题有点儿像鸭,,,反正肯定就都想到倍长然后SA拍个序嘛先 然后就做完了,,,我发现SA的题刷起来特别susi,,,基本上紫题级别的都just一个模板就欧克了最 ...
- cnblogs
想注册个博客园来着的,看着大佬们的博客都十分漂亮,但是发现我因为太菜没有办法搞定美化问题. 以后再说吧 写写东西,反正也没人看,但是写的时候尽量按给别人看的格式写吧 2019.3.15 开通博客 计划 ...
- C++ STL学习之 空间配置器(allocator)
众所周知,一般情况下,一个程序包括数据结构和相应的算法,而数据结构作为存储数据的组织形式,与内存空间有着密切的联系. 在C++ STL中,空间配置器便是用来实现内存空间(一般是内存,也可以是硬盘等空间 ...
- ADB——查看手机设备信息
查看设备信息 查看手机型号 adb shell getprop ro.product.model 查看电池状况 adb shell dumpsys battery ''' Current Batter ...