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() ...
随机推荐
- 2018版OCP考试052最新题库及答案-35题
35.Your database is using Automatic Memory Management. Which two SGA components must be managed manu ...
- form在模版中的渲 染方式
链接:https://www.jianshu.com/p/46b2aa2d5a23 form.as_p 渲染表单为一系列的p标签,每个p标签包含一个字段: <p> <label fo ...
- JAVA将秒的总和转换成时分秒的格式
public static void main(String[] args) { String str = "221"; int seconds = Integer.parseIn ...
- vue-cli中的webpack打包配置
如下: assetsSubDirectory: 'static', assetsPublicPath: '/projectName/', 其中assetsSubDirectory是代表服务器上的实际路 ...
- docker安装MySQL软件
1 搜索mysql镜像 $ sudo docker search mysql NAME DESCRIPTION STARS OFFICIAL AUTOMATED mysql MySQL is a wi ...
- CocoaPods的PodSpec.json文件用法
最近有时候用最新的CocoaPod的第三方库,有时候发现CocoaPod.org能搜到那个Podfile,但是每次在终端Pod search xxx,每次都搜不到,原来是本地的Podspec没用更新, ...
- 获取dataGridView双击时判断双击的是下面的行,还是列头
private void dataGridView1_DoubleClick(object sender, EventArgs e) { Point hit = this.dataGridView1. ...
- 51 Nod 1067 博弈 SG函数
1067 Bash游戏 V2 1 秒 131,072 KB 10 分 2 级题 有一堆石子共有N个.A B两个人轮流拿,A先拿.每次只能拿1,3,4颗,拿到最后1颗石子的人获胜.假设A B都非常聪 ...
- LTE
LTE (telecommunication), Long Term Evolution, a telephone and mobile broadband communication standar ...
- 求两个数a、b的最大公约数
//求两个数a.b的最大公约数 function gcd(a,b){ return b===0?a:gcd(b,a%b) }