zoukankan      html  css  js  c++  java
  • OO第二单元总结

    OO第二单元总结

    设计策略

      这三次作业,我都采取了类似的设计策略。首先由LiftInput线程来从外界获取请求,并放入requestQueue(请求队列)。然后LiftController线程从requestQueue中按顺序取出请求,通过调度算法分配给LiftDatas(电梯信息表,每部电梯都有一份独立的电梯信息表)任务,并通知Lift线程。Lift线程唤醒后从LiftDatas中获取任务,并执行。一层楼为一个周期,完成一个周期动作后,改变LiftDatas中电梯状态信息,唤醒LiftController线程,并继续询问LiftDatas看是否有已分配的任务。后期增加只是在控制器中的任务分配算法要考虑到不同的电梯,从第一次作业的一对一变成了一对多,其他设计策略基本没变,得到了很好的继承。

      我的设计大体可以看成两个生产者-消费者模式的组合。第一对是LiftInput(生产者)- LiftController(消费者),共享容器为requestQueue。第二对是LiftController(生产者)- Lift(消费者),共享类为LiftDatas

      UML时序图如下所示:(由于任务不同,各次作业中LiftDatas、Lift、LiftController的创建线程略有不同,下图为第七次作业中的创建关系)

      在性能设计方面,第一次作业中我采取了优先服务最先到达的乘客。简单概括为:电梯中无乘客时,优先去接最近的乘客;电梯中有乘客时,优先服务到达楼层最近的乘客。同时经过楼层中有等待的乘客就捎带。这个调度算法的性能并不是特别高。从局部上看,每次服务的对象都是最近的乘客,但从全局上来看,这种调度并非最优,存在往复路程,浪费了时间。第二次作业由于要考虑多电梯综合性能,我采取的方法是将新增乘客分配给增加该新增乘客后,总运行时间最短的电梯。为了比较容易地计算运行时间,单个电梯任务在分配后就不会变化,只是将新增乘客做一个类似插入的任务规划,而不是像第一次作业动态地规划任务。导致这种方式在单电梯的性能特别低。但是在3部及3部以上的多电梯调度中,由于任务分配均匀,性能就能达到比较优秀的水平。第三次作业由于电梯数至少保持在3部,因此我继续保留了第二次作业的分配算法。但是由于要求的增加,在分配时针对不同类型的电梯增加了一些限制,直接排除无法到达的电梯。同时涉及换乘问题,由于没有比较好的动态调节算法(能力太差写不出来),我就简单粗暴地将换乘楼层设置为了1层和15层,哪个换乘楼层近,就选哪个换乘楼层。

    SOLID设计原则

    首字母指代概念
    S 单一功能原则 认为对象应该仅具有一种单一功能的概念。
    O 开闭原则 认为“软件体应该是对于扩展开放的,但是对于修改封闭的”的概念。
    L 里氏替换原则 认为“程序中的对象应该是可以在不改变程序正确性的前提下被它的子类所替换的”的概念。参考契约式设计。
    I 接口隔离原则 认为“多个特定客户端接口要好于一个宽泛用途的接口”的概念。
    D 依赖反转原则 认为一个方法应该遵从“依赖于抽象而不是一个实例”的概念。 依赖注入是该原则的一种实现方式。

     个人认为本次作业中Lift类写的最好。整体来说对S,O,L,D的把握较好,但是在这几次的作业中I并未很好地体现。Lift和LiftController两个线程在LiftDatas的交互是比较频繁的,可以考虑使用多个接口来进行交互。相较于第一单元的作业,我发现由于在本单元的设计较好地符合了SOLID设计原则,因此在本单元的作业中处于一个迭代开发的过程,而并非像第一单元的次次重构,减少了许多不必要的作业量。但是类与类之间的交互现得比较复杂,在更加深入理解和晚上程序接口方面,可以使程序各个功能接口更加明确。

    具体分析

     第五次作业

     类图

     

    复杂度分析

     

     数据度量

     

     

    第六次作业

    类图

    复杂度分析

     

     数据度量

     

     第七次作业

    类图

    复杂度分析

     

     数据度量

     

     

     综合分析

    从三次作业的分析图表中可以看出,本次作业对于输入线程,电梯,电梯控制器,乘客,电梯信息表的抽象是比较到位的。每个类的功能职责十分明确。符合面向对象的编程思想。但是从分析中也可以看出,在调度时,计算新增乘客后的运行时间,以及分配新增乘客,这个过程集中在三个方法里。这个过程十分复杂, 但是我并没有拆分,导致写代码时也发生了一个类的行数超标的问题。这三个类的复杂度也是非常高的。这是我需要改进注意的。而其他方法完成得就比较好,做到了“短小精悍”。

    我方bug

    三次作业中,只有第六次作业我方程序被发现bug。这次bug在作业提交截止前已经被我发现,但是迟迟无法定位到错误处,导致提交的作业中存在bug,被同room的同学发现。这个bug是关于waitingPassengers容器的安全问题,在第六次作业中我将第五次作业中一个大的synchronized块拆成多个小的synchronized块时未将waitingPassengers容器保护,导致了有很低的概率会发生线程冲突问题。

    他人bug

    在三次作业中,我均未测出他人bug。但是同room别的同学有发现bug。出现的bug大都是在跨度特别大的间隔中会出现超时。而我的自动评测机生成的数据未覆盖此范围,导致未发现bug,是我在考虑测试数据时的疏忽。

    心得体会

    首先在多线程设计方面,第五次作业从零开始,久久不知从何入手。所以仿造课件写了一个生产者-消费者模式,在此基础上慢慢改造,经过多次修改重构之后,完成了第五次作业。此后随着对多线程设计模式的理解加深,以及上一单元的经验积累。编写的代码都比较符合SOLID设计原则,以致后一次作业都是在前一次的基础上迭代开发,大大减少了我的代码编写量。

    在线程安全方面,我对绝大部分方法都加上了锁,一次的bug是一时不小心的疏忽。死锁问题并未出现,但是在第五次作业编写过程中出现了比较多的“死等”情况。不过随着之后深入得理解,也并没有出现线程方面的问题。不过在这方面,我还是存在着一些小问题。回看代码时可以发现,我重复加了很多锁,以及很多锁并没有必要加。这个是我在以后编写程序时要注意的情况。虽然在本单元的作业中,过多的锁并不会导致性能分的丧失,但是实际程序还是存在着不必要的性能损失。

  • 相关阅读:
    Algorithm Gossip (48) 上三角、下三角、对称矩阵
    .Algorithm Gossip (47) 多维矩阵转一维矩阵
    Algorithm Gossip (46) 稀疏矩阵存储
    Algorithm Gossip (45) 费氏搜寻法
    Algorithm Gossip (44) 插补搜寻法
    Algorithm Gossip (43) 二分搜寻法
    Algorithm Gossip (42) 循序搜寻法(使用卫兵)
    Algorithm Gossip (41) 基数排序法
    Algorithm Gossip (40) 合并排序法
    AlgorithmGossip (39) 快速排序法 ( 三 )
  • 原文地址:https://www.cnblogs.com/MuZiShuiYi/p/12726607.html
Copyright © 2011-2022 走看看