oo第二次作业总结

OO作业第二次总结

多线程电梯

设计策略

这是一个典型的生产者消费者模型,但由于是第一次进行多线程的编写,不知道如何下手。但至少我知道了首先要构造生产者、托盘、调度器以及消费者。作为资源共享区的托盘一开始十分让我头疼,我们要保证我们的托盘是线程安全的,因为我们既要往里放东西,又要从里面取东西,什么wait,什么notifyall,总之很烦。好在接触了优秀的阻塞队列,就不需要自己造轮子了!

  • Main:主线程,相当于生产者,在主线成立生产数据,并加入到阻塞队列中;
  • Scheduler:调度器线程,用来不间断扫描托盘,将可响应的请求分配给最合适的电梯;
  • Req:请求类,用来封装一个请求,相当于c语言中的结构体,同时有很多个接口可以用来访问相应的属性参数;
  • Elevator:电梯线程类,记录了电梯的属性:编号,状态,运动量等等,run方法内是模拟电梯运行,每隔\(3s\)更新一次电梯的状态和运动量;
  • InputHandler:用来处理输入,解析出入的字符串;

度量分析

  • COB:对象之间的耦合性;
  • DIT:继承树的深度;
  • LCOMLack of cohesion method(不知道怎么翻译,缺乏凝聚的方法?)
  • NOC:子类的数目;
  • RFCResponse for class
  • WFCweight method complexity(方法复杂度);

其中我的电梯类的方法复杂度是最高的,电梯类中的方法有:

  • run:模拟电梯运行,更新电梯状态;
  • judgeIncidentForMain:判断是不是主请求可稍待的请求;
  • getReq:获取请求;
  • turnOnE:打开电梯内请求的某一层的按钮的灯;
  • turnOnF:打开楼层间按钮的的上行或者下行按钮的灯;
  • whetherOnE:判断该层楼的电梯内按钮是否是亮着的;
  • whetherOnF:判断该层楼的楼梯间按钮的上行或者下行按钮是否亮着;
  • getMetric:获取该电梯的运动量;
  • canIncident:判断该请求是否是可以被捎带的,专门为FR请求设计;
  • isWFS:判断电梯是否是处于等待服务状态;

方法十分之多,但都是是很依赖于电梯的方法。另外Scheduler类的复杂度也稍高是显而易见的。

高内聚低耦合

内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。

耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。

我个人认为,我的电梯模块和调度器模块的内聚做的比较一般,但是问题不大,主要是因为这些方法十分依赖这个对象,几个主要类之间的对象耦合性太高了,这样不好。

自己程序的BUG

  • 没有处理一楼DOWN和二十楼UP的非法请求;

类图

偷个懒,只对最后作业七的类图分析。

文件管理系统

设计策略

由于我们每次都要不断扫描我们的监控范围,因此我们应该为每一个监控对象设置线程。我们要不断改变获取和设置文件对象,因此文件类需要被改造成线程安全类。本次作业的逻辑比较简单。

  • Main:主线程,输入的入口在这里,同时启动其他线程;
  • InputHandler:用来处理输入;
  • Monitor:监控线程,扫描监控范围,触发器在这里响应;
  • SafeFile:线程安全的文件类;
  • Req:请求类,用来封装请求,类似c语言中的结构体;
  • Detail:记录细节信息线程,每隔一段时间写一次detail文件;
  • Summary:记录触发器触发次数;
  • TestThread:测试线程;

度量分析

对象之间的耦合性最高的是Monitor类是不出意料的,它既要从主线程那里获得请求,又要将数据传递给SummaryDetail类来做记录工作,降低耦合性是接下来要做的工作。方法复杂度最高的是Monitor类也是情理之中的。

自己程序的BUG

  • 监控范围一样的对象但是触发器或者任务不一样的都算作不一样的,关于这个bug指导书我是理解正确了的,但是写的时候还提醒了一下自己,结果最后还是忘记了,主要怪自己没有认真自测,很难受;

类图

多线程出租车

设计策略

本次作业的设计思路十分简单,Main作为生产者输入请求,并产生一百辆出租车先线程,启动每一辆出租车,启动调度器线程。

在调度器中需要完成的就是为每个请求分配抢到该条请求的出租车,然后在这些出租车中选出最符合要求的那一辆,并将该条请求传递给该辆租出车,接着出租车就根据这条请求进行驾驶。

  • Main:主线程,具有生产者的功能,输入的请求在这里解析,然后给到阻塞队列reqList中去,同时在主线程中,生成一百辆出租车,并将其保存在taxiList中;
  • Req:请求类,将一个请求封装,在这个请求类中,我们可以获取一个抢到单的出租车的竞争队列,并在三秒窗口期结束之后,选择最优的出租车;
  • Taxi:出租车线程类,在这个类中,也是将出租车进行了封装,我们可以在wait状态时,随机选择租出车行驶的方向,在接到单之后,选择任意一条最短路径去行驶,在接到客之后,再任意选择一条最短路径行驶到目的地;
  • Scheduler:调度器类,在这个线程类中,我们将不断的扫描我们的请求队列和出租车队列,每一个请求扫描一遍出租车,将可抢单的出租这加入到该条请求的竞争队列中,当某条请求窗口时间结束,那么将该条请求派单给选出的最优出租车;
  • Map:地图类,用来将输入的地图文件初始化,存入到一个二维数组中,并且判断输入的文件是否是正确的’
  • gui:工具集合,就不做过多的介绍了;

度量分析

  • Taxi类与其他类之间的耦合性太高了,应该降低;

自己程序的BUG

  • 出发地和目的地的位置相同的请求没有处理;
  • 没有完美达到\(200ms\)时间间隔。。。。。。

类图

在这个类图中很清晰的展示出了数据间的共享传递情况,Map类中接受Main中打开的map文件,并将其做好处理之后存储下来;Scheduler类中获得在Main的输入的请求队列reqList和产生的出租车队列taxiList,每一个Req类先获得从Main中得到的数据,又在调度过程中获得可以抢到该条请求的Taxi,并加入到自己的出租车竞争队列中去。

怎么找别人的BUG

  • 虽然输入的合法性基本在公测中已经测试过了,但还是可能存在漏网之鱼,我们可以通过其他***钻的角度找到错误;
  • 思考可能的crash情况;
  • 做一些基本的功能性测试;
  • 阅读代码从两个角度寻找是否可能出现错误,其一是线程安全,其二是设计逻辑是否正确。

心得体会

随着写过的oo作业的增多,代码量的增加,我对面向对象的程序设计和多线程程序的编写的熟练度得到了提升。因此感觉这几次的作业不是很费力。

最重要的是要早做准备,我们应该在写之前设计这次作业的思路和逻辑。我总是在写之前,和小伙伴们先讨论好整个作业的设计框架,每一个环节的逻辑应该是怎样的,为后面程序的编写带来了很大的方便。

posted @ 2018-05-02 14:39  paradox_town  阅读(244)  评论(0编辑  收藏  举报