OO第二单元总结

基于度量来分析自己的程序结构

三次电梯作业都是多线程,第一次是单电梯傻瓜策略,第二次是单电梯ALS策略,第三次是多电梯ALS策略。层层递进,但是设计理念不变,
依旧是将调度与电梯执行分离,每个电梯一个线程,输入一个线程,二者共享一个请求队列,在请求队列中实现调度算法。
基于此我用度量来分析自己的程序结构度量类的属性个数、方法个数、每个方法规模、每个方法的控制分支数目、类总代码规模计算经典的OO度量画出自己作业的类图,具体如下

Complexity Metrics(复杂度分析)

这部分我们需要使用的主要是方法的复杂度分析。
方法的复杂度分析主要基于循环复杂度的计算。循环复杂度是一种表示程序复杂度的软件度量,由程序流程图中的“基础路径”数量得来。

  1. ev(G):即Essentail Complexity,用来表示一个方法的结构化程度,范围在[1,v(G)]之间,值越大则程序的结构越“病态”,其计算过程和图的“缩点”有关。
  2. iv(G):即Design Complexity,用来表示一个方法和他所调用的其他方法的紧密程度,范围也在[1,v(G)]之间,值越大联系越紧密。
  3. v(G):即循环复杂度,可以理解为穷尽程序流程每一条路径所需要的试验次数。

对于类,有OCavgWMC两个项目。

  1. OCavg:类的方法的平均循环复杂度。
  2. WNC:类的方法的总循环复杂度。

Dependency Metrics(依赖度分析)

  1. Cyclic:指和类直接或间接相互依赖的类的数量。这样的相互依赖可能导致代码难以理解和测试。
  2. DcyDcy:计算了该类直接依赖的类的数量,带表示包括了间接依赖的类。
  3. DptDpt:计算了直接依赖该类的类的数量,带表示包括了间接依赖的类。

第一次作业

第一次作业很简单,输入线程为主线程,再开一个电梯线程,二者共享一个终止变量和一个请求队列,队列支持添加与
取出操作,电梯按照傻瓜调度,当输入为none时,设置终止变量并终止输入线程。当且仅当电梯线程判断终止变量为终止且请求队列空时,电梯
线程终止。类图如下所示

度量表如下所示


第二次作业

此次作业要求ALS调度,所以输入线程不变,只需要修改电梯线程的运行规则即可,同时在请求队列中添加调度器机制,
负责处理捎带服务,类图如下所示。

度量表如下所示


第三次作业

这次作业依旧可以延续上次的框架,具体见如下类图

度量表如下所示


基于SOLID原则的评价

SRP(单一责任原则):避免类的功能重合和一个类做太多事。

有调度器、电梯、输入、阻塞队列、换乘单元这5种类,3类线程。电梯类要做的事情有点多,整体的代码量也比较大,接近300行。换乘单元被4个线程共享(调度器+3*电梯),这里的设计不太好,最好改成单例模式。

OCP(开放封闭原则):对扩展开放,对修改封闭。

电梯的属性是new的时候传入构造的。其实可以把电梯公共的部分做成一个抽象的父类,三类电梯分别继承这个公共的父类,可以提高扩展性。

LSP(里氏替换原则):子类应该包括父类的所有属性。

木有继承。

ISP(接口分离原则):避免接口的责任重合和一个接口做太多事情。

木有设计接口。

DIP(依赖倒置原则):模块之间尽可能依赖于抽象实现,而不是模块之间的依赖,抽象不能依赖于细节。

主要就是换乘单元被太多的线程共享使用,这块耦合度太高,不是一个好的设计。

bug分析

这一单元的主要内容在于多线程,而由于多线程的不确定性与不可复现性,众多的bug都会集中在多线程这一块。
强测出现bug主要是因为发生了死锁。排查后发现问题在于在添加请求这一方法上偶然出现互相持有资源导致。
调整synchronized的范围,使死锁的必要条件消失(请求资源前放弃资源)解决了bug。在设计程序时没有
预防死锁这一bug的出现,说明对线程同步的考虑仍然不够周到。然而失败是最好的老师,在这一次作业完成后,
认识到构思程序时,应更加谨慎、全面地考虑线程安全问题。

心得体会

线程安全:
我认为要保证线程安全,最重要的是以下几点:

  1. 尽可能减少共享对象的数量(降低耦合)
  2. 保证共享对象的访问、写入、删除等操作是互斥的
  3. 理清线程之间的同步、互斥关系
posted @ 2019-04-24 12:04  Arrow0  阅读(194)  评论(0编辑  收藏  举报