OOP 第二章作业总结
实现策略
这里结合一下我画的第三次作业的时序图(可能有画的不好的地方)来叙述一下我的实现逻辑。最开始主线程负责创建必要的线程(输入、调度线程)与请求队列类实例;输入线程负责与人进行交互,将获取到的请求放入请求队列;调度线程则每次从请求队列中取出一个请求,将其分发给三个电梯,若需要拆分,则新建一个次级调度线程,将第二部分的请求的分发任务交给它来实现;电梯线程只需要负责模拟自己电梯的运行即可。
本次作业共享数据的同步互斥主要采用的是 synchronized 方法,再配以 wait notifyAll 等通信方法,完成了线程之间的协作。
程序结构分析
类图分析
第一次作业类图分析
主函数类负责创建电梯线程和输入线程,Request 类负责实现请求队列的功能,Input 类负责将输入的请求放到请求队列里面,电梯线程负责调用 ELevator 类实现的方法来模拟电梯运行。感觉这样设计还挺合理的。
第二次作业类图分析
在上一次设计之上,将 ElevatorRun 类的功能(模拟电梯运行线程)放到 Elevator 类里,新增 Schedule 类充当调度器,即将请求队列中的请求取出并分发给电梯线程,并且由它创建电梯线程,主类只负责创建 Schedule 和 Input 两个线程。其余地方设计与上一次作业一样。
第三次作业类图分析
- 在上一次设计之上,将原有的 Request 类重命名为 ReqQueue 更符合该类所实现的功能。
- 新增 Request 类,这个类是为了复制 PersonRequest 类并向其中增添了 Finish 位,来标志当前请求是否被解决了,这一点在拆分请求中对于第二条请求的阻塞条件判定会用到。(这里用代理的话,就能更简单的实现)
- 新增 SubSchedule 类用于实现拆分请求的二级调度。
在本次作业中,对于请求拆分的处理,我是想实现一个二级调度,当需要拆分的时候,新建一个子调度线程(让他负责拆分后请求的第二部分的分发)。按道理来说,子调度类应该是主调度类的子类,但是我当时认为没有必要再为子调度类复制主调度类的那些成员域,感觉只需要调用主调度类的分发请求的方法就可以了,所以就让主调度类成为了子调度类的一个成员变量,但这样一来又有违于主子这个概念,感觉还是继承要好一点。
代码静态分析
- 由于是 eclipse 用户,所以代码静态分析使用的是 Designite jar 包。
- 三次作业的类复杂度分析
- 三次作业的 LCOM、FANIN、FANOUT 指标都非常相近,LCOM 指标小这点是好的,但是后面两个指标都为 0,表明了我的结构并没有按照分层设计这三次作业,更多的是平级的互相合作,这一点在后续的作业中有待改进。(但总觉得也不至于为 0 吧,有点质疑这个分析包)
- 三次作业的方法复杂度来说,CC 指标较上一次有显著的下降了,第一次平均值是1.3,最大值是4;第二次平均值是2.5,最大值是8;第三次作业平均值是2.7,最大值12。
- 第二次作业 CC 值最大的方法是 Elevator 类的 deal 方法,该方法模拟电梯接送乘客,所以每到一层需要判断是否开门,以及最后一个电梯里的乘客送达之后,判断等待队列里面是否有乘客需要接送,有则将其视为主请求,并接着运行。仔细想了一下,里面确实有一些判断语句能够用一个方法封装起来,这样既提高代码复用性,又能够降低复杂度。
- 第三次作业 CC 值最大的方法便是 Schedule 分发请求的方法,因为这个方法需要判断一个请求,是能给哪一个电梯,或者需要拆分,而这个做出判断的过程,我是使用了一个大的 switch 判断语句,故 CC 复杂度过大,但是感觉这个是不得已的事情。
- 三次作业的 code smell 分析
- Magic Number:三次作业中随着作业的难度的递增,魔数出现的数量逐渐增加,到了第三次已经有了 33 次了,检查了一下代码,主要出现在 Elevator 与 Schedule 类,确实有很多地方可以改为宏定义的方式,下一次需要注意,有助于提高代码可读性。
- Complex Conditional:这个主要出现在第二次和第三次作业中的电梯请求分发的判断地方与电梯开关门逻辑之中。对于后者有改进之处,因为我是把判断有没有人要上来与出去的语句分别放在了开关门方法里面,这一处应该拆分一下职能。
自我程序 bug 分析
- 后两次作业分别被找出一处 bug
- 第二次作业:bug 是在电梯运行模拟处,完全是逻辑错误,在两个地方改变了电梯的 aimFloor 但是 direction 并没有改变,导致电梯上天了。
- 第三次作业:bug 是我的线程在评测机上出现了线程不稳定的情况,反正本地是跑出来没问题,原因是我 的次级调度中心,在获悉前一部分请求结束之后,先告诉主调度器自己结束了再分发的请求,这导致了主调度器在确认所有次级调度器结束之后就直接让电梯下班了,这时若分发工作还未完成则会有提早下班的情况。
发现他人 bug 策略
- 其实互测都是挺佛了,主要就靠随机生成数据,然后靠网上的评测机来验证输出的正确性(由于自己感觉写评测机太麻烦就咕了,逃)
心得体会
- 在设计框架上,现在至少想到有两处可以改进的地方:
- 用工厂方法,实现生成不同种类的电梯:这个主要是由于第二次作业就没有想到以后电梯会不同的情况,所以就把电梯写死了,然后第三次并不想重构电梯。应该可以在电梯类里面定义实现好业务逻辑,然后通过继承的方式,来实现不同类别的电梯,这样才符合开闭原则。
- 在第三次作业的时候,由于我想扩展 PersonRequest 类的功能,实现一个结束标识符,我重写了一个 Request 类,这非常不优雅,其实可以用动态代理实现的,这样就不用傻傻的重抄一遍了(虽然就工作量而言,可能都是差不多的)。关于代理模式,我总结在了另一篇博文中 Java 设计模式 -- 代理模式
OOP 第二章作业总结的更多相关文章
- SQL 第二章 作业
/*第二章 作业*/ create table S ( sno char(2) NOT NULL UNIQUE, sname char(3), city char(2) ); alter table ...
- OOP 第一章作业总结
程序设计结构分析 类图分析 第一次作业 由于第一次作业完成的功能比较简单,而且出于对面向对象设计理念不熟悉(其实现在也不是很熟悉,逃),整个程序设计的非常简单.通过类图(见下)可以看出,程序只有两个类 ...
- OOP第二章博客
OO第二次博客作业 (1)作业分析 三次作业在处理多线程的协同配合时都是使用将同步放在自己写的"线程安全类"(经测试有些许漏洞_,但是不影响结果就是了): 我个人倾向于把wait( ...
- 我永远爱着OOP——第二单元作业总结
第二单元的电梯真是愉♂快呢,多线程编程作为java编程OOP中的重要组成部分,通过这一个单元的学习,我也是有了很多全新的认识 那么下面就先例行一下公事 三次作业分析 第五次作业 设计分析 实现的电梯是 ...
- Java OOP——第二章 继承
1. 继承: ●继承是面向对象的三大特征之一,是JAVA实现代码重用的重要手段之一: ●继承是代码重用的一种方式,将子类共有的属性和行为放到父类中: ●JAVA只支持单继承,即每一个类只有一个父类,继 ...
- java OOP第二章_封装
一. 封装: 属性通过private访问修饰符将其设置为私有的,只有当前类中可以访问,同时提供通过public访问修饰符的公共方法可以给任何类中访问. 通常针对属性提供公共的setter方法进行赋值, ...
- 第二章作业-第3题(markdown格式)-万世想
第3题题目是: 完成小组的"四则运算"项目的需求文档(使用Markdown写文档),尝试同组成员在各自PC上修改同一文档后,如何使用Git命令完成GitHub上的文档的更新,而不产 ...
- oop第二章1知识点汇总
1 方法重写必须满足以下要求: 1 重写方法与被重写的方法必须方法名相同,参数列表相同. 2 重写方法与被重写的方法返回值类型必须相同或是其子类 3 重写方法不能缩小被重写方法的访问权限 2 重载和重 ...
- C++第二章作业
1.(1)if...else 用法 #include <iostream> #include <cstring> using namespace std; int main() ...
随机推荐
- dataframe初始化
- day11学python 多线程+queue
多线程+queue 两种定义线程方法 1调用threading.Thread(target=目标函数,args=(目标函数的传输内容))(简洁方便) 2创建一个类继承与(threading.Threa ...
- jquery源码解析:pushStack,end,ready,eq详解
上一篇主要讲解了jQuery原型中最重要的方法init.接下来再讲一些比较常用的原型方法和属性 core_slice = [].slice, jQuery.fn = jQuery.prototype ...
- LVM 认知与扩容操作
继上次 "Linux系统如何迁移至LVM磁盘"反响不错,近三百的访问量吧.这次想续写点东西,主要讲的是"LVM认知和扩容操作".因为网上大多数不准确,可能作者也 ...
- Easyui里面动态设置输入框的可见性
JQuery EasyUI 动态隐藏 一.隐藏datagrid某一列 $('#dg').datagrid('hideColumn', 'field'); 二.隐藏html的lable.input标 ...
- Python实现——二层BP神经网络
2019/4/23更新 下文中的正确率极高是建立在仅有50组训练数据的基础上的,十分不可靠.建议使用提供的另一个生成训练集的generate_all函数,能产生所有可能结果,更加可靠. 2019/4/ ...
- ARC初步介绍
[转载自 http://onevcat.com/2012/06/arc-hand-by-hand/] 手把手教你ARC——iOS/Mac开发ARC入门和使用 Revolution of Objecti ...
- Mac环境下安装python库时出现ModuleNotFoundError: No module named 'XXX'
在使用pip3安装爬虫的一些有关库时发现安装成功后,import时发现又找不到,后来发现一个解决方法. 在Anaconda-Navigator里面打开environment里面寻找发现真的没有,这时再 ...
- 对cookie,session,token,jwt的理解
对这几个东西有点凌乱了,今天有时间整理下 cookie Cookie的诞生 由于HTTP协议是无状态的,而服务器端的业务必须是要有状态的.Cookie诞生的最初目的是为了存储web中的状态信息,以方便 ...
- 子元素margin-top为何会影响父元素?
子元素margin-top为何会影响父元素? 引用地址:https://blog.csdn.net/sinat_27088253/article/details/52954688 2016年10月28 ...