OO面向对象编程:第二单元总结

OO面向对象编程:第二单元总结

第一次作业

1.需求分析

本次作业需要模拟一个多线程实时电梯系统,从标准输入中输入请求信息,程序进行接收和处理,模拟电梯运行,将必要的运行信息通过输出接口进行输出。即一个单部多线程傻瓜调度(FAFS)电梯

在第一次电梯作业中,我采取的是生产者--消费者的模式,将请求队列(我使用了Arraylist类)作为共享对象存储在调度器中,调度器为单例模式,被输入线程和电梯线程共享;输入线程和电梯线程在同一时间点只能有一个访问请求队列。即给相应的在两个线程中的读写操作上了队列的对象锁。

2.度量分析

参数解释:

程序分析使用IDEA JAVA的插件Calculate Metrics对每次作业的类和方法进行基于度量的复杂度分析,当然,首先最重要的是搞懂主要的三个参数的意义。

1)ev(G) :Calculates the essential complexity of each non-abstract method. Essential complexity is a graph-theoretic measure of just how ill-structured a method's control flow is. Essential complexity ranges from 1 to v(G), the cyclomatic complexity of the method. (即表示一个方法的结构化程度,值越大则程序结构越“病态”)

2) iv(G):Calculates the design complexity of a method. The design complexity is related to how interlinked a methods control flow is with calls to other methods. Design complexity ranges from 1 to v(G), the cyclomatic complexity of the method. Design complexity also represents the minimal number of tests necessary to exercise the integration of the method with the methods it calls. (即表示一个方法与其调用的其他方法的紧密程度,值越大则越紧密)

3)v(G):Calculates the cyclomatic complexity of each non-abstract method. Cyclomatic complexity is a measure of the number of distinct execution paths through each method. This can also be considered as the minimal number of tests necessary to completely exercise a method's control flow. In practice, this is 1 + the number of if's, while's, for's, do's, switch cases, catches, conditional expressions, &&'s and ||'s in the method. (即表示一个方法的穷尽每一条路径所需要的次数,也就是循环复杂度)

4)OCavg :Calculates the average cyclomatic complexity of the non-abstract methods in each class. Inherited methods are not counted for purposes of this metric.

5)WMC :Calculates the total cyclomatic complexity of the methods in each class.

类度量:

方法复杂度度量:

类图:

3.设计原则检查

  • Single Responsibility Principle:类/方法的功能行为单一,符合该原则。

  • Open Close Principle:一定程度上考虑了可拓展性,但依照开闭原则应该进一步增加框架弹性。

  • Liscov Substitution Principle:无子类无继承,满足里氏替换原则。

  • Interface Segregation Principle:无接口设计,满足接口分离原则。

  • Dependency Inversion Principle:对楼层建模不够细致,需要进一步改进一满足本原则。

4.BUG分析

在中测和强测均得到满分,暂时未发现bug

补充说明:(自测过程中的发现)

  • 线程安全问题

    在本次作业的实现过程中,由于使用了Arraylist队列,以及使用暴力轮询,因此并没有显式使用synchronizedReentranlock`等JAVA锁机制来保证线程安全。由于任务简单,因此没有出现bug,但事后来看还是应该进行显式使用锁机制,一是为了避免未知不定的线程不安全,二是在可读性和代码含义上显式使用锁机制能够起标识警示作用。

  • 测试问题

    多线程程序设计的另一大难点就是调试。由于线程执行的不确定性以及程序调试断点的特殊性(断点的设置可能会影响线程的行为),因此多线程程序的测试比单线程程序更加繁琐。

第二次作业

1.需求分析

本次作业,需要完成的任务为单部多线程可捎带调度(ALS)电梯的模拟。

本次作业需要模拟一个多线程实时电梯系统,从标准输入中输入请求信息,程序进行接收和处理,模拟电梯运 行,将必要的运行信息通过输出接口进行输出。

本次作业电梯系统具有的功能为:上下行,开关门,每运行一层的时间为固定值,开关门的时间为不同的固定值

电梯系统可以采用任意的调度策略,即上行还是下行,是否在某层开关门,都可自定义,只要保证在系统限制 时间内将所有的乘客送至目的地即可。

电梯系统在某一层开关门时间内可以上下乘客,开关门的边界时间都可以上下乘客

ALS(可捎带电梯)规则介绍

  • 可捎带电梯调度器将会新增主请求被捎带请求两个概念

  • 主请求选择规则:

    • 如果电梯中没有乘客,将请求队列中到达时间最早的请求作为主请求

    • 如果电梯中有乘客,将其中到达时间最早的乘客请求作为主请求

  • 被捎带请求选择规则:

    • 电梯的主请求存在,即主请求到该请求进入电梯时尚未完成

    • 该请求到达请求队列的时间小于等于电梯到达该请求出发楼层关门的截止时间

    • 电梯的运行方向和该请求的目标方向一致。即电梯主请求的目标楼层和被捎带请求的目标楼层,两者在当前楼层的同一侧。

  • 其他:

    • 标准ALS电梯不会连续开关门。即开门关门一次之后,如果请求队列中还有请求,不能立即再执行开关门操作,会先执行请求。

2.度量分析

类度量:

方法复杂度度量:

类图:

3.设计原则检查

  • Single Responsibility Principle:类/方法的功能行为单一,符合该原则。

  • Open Close Principle:相比第一次作业增加了拓展性,较符合开闭原则。

  • Liscov Substitution Principle:无子类无继承,满足里氏替换原则。

  • Interface Segregation Principle:无接口设计,满足接口分离原则。

  • Dependency Inversion Principle:对楼层进行建模,较符合本原则。

4.BUG分析

在中测和强测均得到满分,暂时未发现bug

补充说明:(自测过程中的发现)

  • 线程安全问题

    在本次作业的实现过程中,由于使用了Arraylist队列,以及使用暴力轮询,因此并没有显式使用synchronizedReentranlock`等JAVA锁机制来保证线程安全。由于任务简单,因此没有出现bug,但事后来看还是应该进行显式使用锁机制,一是为了避免未知不定的线程不安全,二是在可读性和代码含义上显式使用锁机制能够起标识警示作用。

  • 测试问题

    多线程程序设计的另一大难点就是调试。由于线程执行的不确定性以及程序调试断点的特殊性(断点的设置可能会影响线程的行为),因此多线程程序的测试比单线程程序更加繁琐。

第三次作业

1.需求分析

第3次作业要求实现多部多线程智能(SS)调度电梯,进一步考察面向对象多线程程序的设计能力,重点关注多线程协同、线程安全与面向对象抽象设计、拓展设计的结合考察。

本次作业需要模拟一个多线程实时多电梯系统,从标准输入中输入请求信息,程序进行接收和处理,模拟电梯运行,将必要的运行信息通过输出接口进行输出。

本次作业电梯系统具有的功能为:上下行,开关门。本次多部电梯的可停靠楼层,运行时间,最大载客量都不相同

电梯系统可以采用任意的调度策略,即上行还是下行,是否在某层开关门,都可自定义,只要保证在系统限制时间内将所有的乘客送至目的地即可。

电梯系统在某一层开关门时间内可以上下乘客,开关门的边界时间都可以上下乘客

电梯最大载客量(轿厢容量)

  • A:6名乘客

  • B:8名乘客

  • C:7名乘客

2.度量分析

类度量:

方法复杂度度量:

类图:

3.设计原则检查

  • Single Responsibility Principle:类/方法的功能行为单一,符合该原则。

  • Open Close Principle:通过拓展增加新的换乘功能,符合开闭原则。

  • Liscov Substitution Principle:对PersonRequest类进行了继承,并在父类出现的地方使用了子类代替,满足里氏替换原则。

  • Interface Segregation Principle:无接口设计,满足接口分离原则。

  • Dependency Inversion Principle:抽象较为细致,符合DIP。

4.BUG分析

这次很尴尬也很无奈强测出现了BUG,我觉得这主要是我再过了中测的所有点之后掉以轻心了,没有考虑到弱侧和中测其实都只是测试强度很低的点。

原因在于,我是直接借用了上一部电梯的大致框架,将只直接拷贝了3遍当做我这次作业的3部电梯ABC,在A中进行的一处修改,是为了防止电梯在一个楼层等待时,如果之前已经输出了ARRIVE到该楼层的信息,那么之后如果是过了一段时间又有人来上电梯的话,那么我就会又输出一点ARRIVE到该楼层的信息,所以评测机会认为我这是不合法的输出。

我在A电梯类中完成了相应的修改,但是却忘记了把它一直到BC电梯类中,所以导致强侧中全部都因为这一个小小的疏忽导致错误,即使在我的调度策略和电梯运行逻辑以及主线程和3个电梯线程完全正确的情况下。

我做了一下改动:主要是加了一个判断的过程,除非楼层变化,否侧不会再输出ARRIVE到当前所在楼层的信息。

 

心得与体会

 

1.Thread的双重职责

•根据功能管理所需对象及其访问

•根据系统设计要求,与其他线程交互(等待/唤醒/…)

2.线程在执行控制上具有独立性

•不具有互相调用关系

•Q:如果我在一个线程方法中调用了另一个线程对象的方法会发生什么?

3.线程之间的关系

•父子关系:创建和启动线程

•协作关系:生产者-消费者

•同步关系:通过共享对象,或者主动状态控制进行同步(wait,notify)

4.访问共享对象是个充满变数的事情

•稍有不慎,程序状态失控

•减少共享

•不得不共享时,同步控制

5.对象锁也是一个神奇的东西

•每个对象有且只有一把锁,控制进入和退出共享“房间”的行为

•对象既可以是“房间”,也可以是一把“锁”

•“房间”和“锁”要配合好

可以使用JVM内置提供的物理锁,也可以自行构造逻辑锁

如何使用锁并不是一个琐碎问题

•线程代码加锁

•中间过程on-demand加锁

•共享对象加锁

 

 

原文地址:https://www.cnblogs.com/chenhaonan-nickyoung/p/10757362.html