北航OO(2020)第二单元博客作业

设计策略分析(多线程视角)

本单元的三次作业中,我采用了相似的策略:采用输入线程与电梯线程通过线程安全的调度器进行交互的方式。这种方式基本属于生产者-消费者模式。在调度器的设计方面,我主要采用synchronized关键字结合wait和notify方法完成互斥访问和同步控制。

Homework 3 SOLID分析与可扩展性分析

Single Responsibility Principle

Elevator类有且仅有一个public方法:run方法,仅仅负责执行电梯的运行逻辑。

Main类有且仅有一个public方法:main方法。但main方法既负责创建线程,又负责输入的处理与结束,具有多重责任。可以采取创建新的输入类和输入线程的方法解决这个设计问题。

Dispatcher类具有多个public方法,但每个方法都有唯一确定的职责,通过下面章节中UML类图即可确认这一特性。Dispatcher类负责将请求放置于每一楼层,供Elevator取用,满足了SRP原则。

FloorConverter类有两个public方法,负责将楼层号与数组下标相互转换,满足了SRP原则。

FloorSelector类有两个public方法,分别用来判断当前层是否可以停靠和选择乘客的目的楼层。这两个职责都需要电梯的停靠信息,而且逻辑联系较为紧密,因此可以置于同一类中完成。

Open Close Principle

本次作业中除继承Thread类外没有使用任何继承,几乎都是通过修改已有实现完成新增功能,违反了OCP原则。

Liskov Substitution Principle

本次作业中除继承Thread类外没有使用任何继承,因此该原则无从体现。

Interface Segregation Principle

本次作业中没有使用任何接口,因此该原则无从体现。

Dependency Inversion Principle

本次作业中除继承Thread类外没有使用任何继承,且没有使用任何接口,因此该原则无从体现。

可扩展性

通过上面的分析可以看出,扩展功能几乎一定需要通过改写已有的实现来完成。但由于类的public方法职责都较为明确,这样的设计可以为功能的扩展带来一定的便利。

基于度量的程序结构分析

Homework 1

代码度量

Type Name Method Name LOC CC PC
Dispatcher Dispatcher 10 2 0
Dispatcher setFinished 6 1 0
Dispatcher addRequest 13 2 1
Dispatcher getRequests 14 2 2
Dispatcher getTask 30 9 1
Elevator Elevator 11 2 1
Elevator run 39 10 0
Elevator stopOnFloor 20 2 1
Elevator getOn 7 2 1
Elevator getOff 7 2 0
Elevator go 10 1 0
Main main 23 3 1
Type Name NOF NOPF NOM NOPM LOC WMC NC DIT LCOM FANIN FANOUT
Dispatcher 5 1 5 5 80 16 0 0 0.0 2 0
Elevator 6 0 6 2 102 19 0 0 0.0 1 1
Main 0 0 1 1 25 3 0 0 -1.0 0 2

类图

本次作业构建了三个类。这些类的封装较好,对外暴露的方法较少,且都具有明确的职责。大部分方法具有明确的职责,也较为简洁。但是,Elevator类的run方法展开了电梯的一次运行逻辑,整体较为复杂;Dispatcher类的getTask方法也较为复杂,不便改动和维护。

Homework 2

代码度量

Type Name Method Name LOC CC PC
Dispatcher Dispatcher 10 2 0
Dispatcher setFinished 6 1 0
Dispatcher addRequest 13 2 1
Dispatcher getRequests 23 6 3
Dispatcher getTask 35 9 1
Dispatcher getUpperTask 8 3 1
Dispatcher getLowerTask 8 3 1
Elevator Elevator 12 2 2
Elevator run 39 10 0
Elevator stopOnFloor 20 2 1
Elevator getOn 7 2 1
Elevator getOff 7 2 0
Elevator go 10 1 0
FloorConverter indexToFloor 7 2 1
FloorConverter floorToIndex 7 2 1
Main main 27 4 1
Type Name NOF NOPF NOM NOPM LOC WMC NC DIT LCOM FANIN FANOUT
Dispatcher 6 1 7 5 111 26 0 0 0.0 2 1
Elevator 8 0 6 2 105 19 0 0 0.0 1 2
FloorConverter 0 0 2 2 16 4 0 0 -1.0 2 0
Main 0 0 1 1 29 4 0 0 -1.0 0 2

类图

本次作业与上一次作业架构极为相似,只是多了FloorConverter类。因此优缺点与上次大体相同,在此不再赘述。

Homework 3

代码度量

Type Name Method Name LOC CC PC
Dispatcher Dispatcher 10 2 0
Dispatcher setFinished 8 2 0
Dispatcher addRequest 13 2 1
Dispatcher elevatorAddRequest 9 2 2
Dispatcher getRequests 12 2 4
Dispatcher filterRequests 19 4 5
Dispatcher decreaseRequestCount 6 2 0
Dispatcher getTask 35 9 2
Dispatcher hasValidRequest 10 3 4
Dispatcher getUpperTask 11 4 2
Dispatcher getLowerTask 11 4 2
Elevator Elevator 28 5 3
Elevator run 40 10 0
Elevator changeDirection 8 2 0
Elevator stopOnFloor 18 2 1
Elevator getOn 10 2 1
Elevator getOff 15 3 0
Elevator go 12 1 0
FloorConverter indexToFloor 7 2 1
FloorConverter floorToIndex 7 2 1
FloorSelector isStoppable 12 4 2
FloorSelector selectFloor 15 5 4
FloorSelector selectFloorA 6 2 1
FloorSelector selectFloorB 18 6 3
FloorSelector selectFloorC 24 8 3
Main main 33 6 1
Type Name NOF NOPF NOM NOPM LOC WMC NC DIT LCOM FANIN FANOUT
Dispatcher 6 1 11 7 152 36 0 0 0.2727272727272727 2 2
Elevator 10 0 7 2 143 25 0 0 0.0 0 3
FloorConverter 0 0 2 2 16 4 0 0 -1.0 3 0
FloorSelector 3 0 5 2 80 25 0 0 1.0 2 1
Main 0 0 1 1 35 6 0 0 -1.0 0 1

类图

本次作业构建了五个类。这些类的封装较好,对外暴露的方法较少,且都具有明确的职责,类间的协作关系也较为明确。大部分方法具有明确的职责,也较为简洁。但是,与前两次作业一样,Elevator类的run方法仍然展开了电梯的一次运行逻辑,整体较为复杂;Dispatcher类的getTask方法也较为复杂,不便改动和维护。

UML时序图

由于三次作业的线程交互模式较为类似,因此统一绘制UML时序图如下。

Bug分析

本单元作业在公测和互测中未出现任何bug。

在第三次作业的开发过程中,由于Dispatcher类的getTask方法和getRequests方法判断请求是否为空的标准不一致,我的电梯线程在一些情况下出现了轮询,导致在中测中出现了CTLE的现象。我在本地通过在JProfiler中观察线程状态及CPU时间,并在程序中打印log的方式,最终定位了bug的位置,并进行了修复。

Hack策略分析

本次作业同第一单元不同,需要做到在线交互。因此,本次作业的测试要求更高。但是,由于摸鱼心切,我仍然采用了手动构造测试用例的方法。因此,本单元我未能发现他人的任何bug。

心得体会:线程安全与设计原则

通过本单元的三次作业,我对Java多线程编程有了一个初步的认识,并了解了一些简单的互斥访问与同步控制的方法。在多线程编程中,通过线程安全的共享对象来完成线程间交互是十分清晰而简洁的方式。通过对象锁,可以使该对象在同一同步块内只能被一个线程访问,且不会被打断。再结合wait和notifyAll方法,可以避免轮询,高效利用CPU资源。此外,在设计中遵循SOLID原则及一些其他重要的设计原则也是十分重要的,这些原则保证了程序结构的清晰性和良好的可扩展性。在本单元作业中,部分设计原则未能体现甚至有所违背,在今后的编程中会多加注意。

(0)

相关推荐

  • BUAA OO 第二单元总结

    BUAA OO 第二单元总结 Part 1 设计策略 这三次作业采用了主线程获取请求,多级调度器逐级分派,电梯模拟运行的策略.具体来说,主线程实例化ElevatorInput类,通过阻塞读取方式获得请 ...

  • BUAA OO Unit2 电梯调度

    这次作业完成了一个开环可选层电梯调度系统.第二次迭代加入了容量限制.多部电梯,第三次迭代加入了电梯楼层分工.增添电梯请求. 1. 系统架构 graph LR MainClass--Requests-- ...

  • 北航OO(2020)第四单元博客作业暨课程总结博客

    目录 北航OO(2020)第四单元博客作业暨课程总结博客 本单元作业的架构设计 架构设计及OO方法理解的演进 四个单元中测试理解与实践的演进 课程收获 关于课程的一些建议 OO线上学习体会 本单元作业 ...

  • oo第二次博客

    前言: 这是一篇面向对象作业总结,作业内容是模拟电梯调度,一共有三个阶段,具体要求不详述,第一阶段只要求先来先服务电梯,第二次支持捎带,第三次则需要多部电梯协调,通过换乘来完成请求.本次作业在优化方面 ...

  • BUAA_OO第一单元总结性博客作业——表达式求导

    一.程序设计思路在我的三次作业中都采用了类的分层结构,采用逐项匹配,分层求导的思路.(一).第一次作业中构建了Polynimial(多项式)类,在类的构造器中就完成了对非法空格的判断并对合法表达式进行 ...

  • 2019年北航OO第2单元(电梯模拟)总结

    2019年北航OO第2单元(电梯模拟)总结

  • 2019年北航OO第一次博客总结

    一.基于度量对程序结构的分析 1. 第一次作业 1.1 基于类的分析的度量 首先,基于类的属性个数,方法个数,每个方法的规模,每个方法的控制分支数目,类总代码规模等特征对本次作业的结构进行分析. 1. ...

  • 2020年最棒的10个鸡尾酒博客和网站

    2020年最棒的10个鸡尾酒博客和网站

  • 参观首博:秘鲁安第斯文明探源 第二单元 上

    参观首博:秘鲁安第斯文明探源 第二单元 上

  • OO第三单元作业总结

    OO第三单元作业总结--JML 第三单元的主题是JML规格的学习,其中的三次作业也是围绕JML规格的实现所展开的(虽然感觉作业中最难的还是如何正确适用数据结构以及如何正确地对于时间复杂度进行优化). ...