oo第二单元总结
第五次作业
(1)基于度量来分析自己的程序结构
类图:
设计了六个类,分别为Ele类,Line类,Main类,Order类,Scheduler类和TestMain类。其中Ele类,Scheduler类和TestMain类,分别为电梯线程,调度器线程和输入指令线程。Line类为请求队列类,Order类为单条指令类。Main类负责实例化一个请求队列对象,一个电梯线程,一个调度器线程,一个输入指令线程。请求队列对象,提取从输入指令线程得到的指令的属性,并通过调用Order类,实例化一个新的指令对象并存储。电梯线程,调度器线程和输入线程,通过共享请求队列对象,来实现程序的协同和控制。输入指令线程,当输入指令为NULL时,会将输入结束的标志传入请求队列对象,并线程结束。调度器线程,则会在请求队列对象的请求队列为空,并且输入结束时,线程结束,否则会在电梯指令为空时,将指令队列的一个指令传入电梯线程。电梯线程,则在识别调度线程结束,并且自身没有指令时,结束线程。
本次作业的设计的优点是,三个线程利于后续程序的扩展。但同时这也是个缺点,因为本次作业并不需要这么多线程。
度量分析:
Metrics图中显示Ele类和Scheduler类的run的代码块的嵌套过深,因为对线程是否结束,是否修改请求队列对象等的判断嵌套过多。
(2)分析自己程序的bug
第五次作业互测出现了一个bug。bug为,当前线程满足结束条件时,线程在wait(),没有notifyAll(),使得线程一直未结束,CPUtime超时。
(3)分析自己发现别人程序bug所采用的策略
依然是通过观看别人代码的方式,但并未发现BUG。
第六次作业
(1)基于度量来分析自己的程序结构
类图:
设计了七个类,比第五次作业多了一个Eleob类,电梯线程和调度器线程共享Eleob对象,Eleob对象会锁住电梯将要执行的指令序列,因此调度器线程会通过Eleob对象判断,是否请求队列有可捎带的指令,若有,则传入电梯线程的指令序列。而电梯线程则通过Eleob对象,判断主请求和当前楼层是否需要执行指令。调度器线程比第六次作业多了判断捎带的方法。剩下的基本与第五次作业相似。
本次作业的设计的优点依然是,三个线程利于后续程序的扩展。但同时这个缺点在本次作业得到了巨大的体现,因为线程过多,出现了线程不安全问题,因此需要仔细谨慎处理冲突,结束等问题。
度量分析:
Metrics图中显示,Ele类和Scheduler类的run的代码块依然嵌套过深,而且Ele类和Scheduler类的圈复杂度过大,因为对wait()和notifyAll()的判断和使用。Scheduler类的addone方法,即判断捎带的方法,的参数数量过多,因为判断是否要捎带的条件过多。
(2)分析自己程序的bug
第六次作业有一个巨大的bug。Bug为,设计上的BUG,对共享对象请求队列对象的wait()和notifyAll()出现了问题,以及对电梯线程的指令序列的保护出现了问题,总结来说,线程出现了不安全问题。
(3)分析自己发现别人程序bug所采用的策略
依然是通过观看别人代码的方式,但并未发现BUG。
第七次作业
(1)基于度量来分析自己的程序结构
类图:
设计了八个类,比第六次作业多了一个Outcon类,三个电梯线程共享Outcon对象,Outcon对象会锁住输出,因此电梯线程会通过Outcon对象避免输出的冲突。同时调度器线程不再负责捎带,只负责将请求队列的指令按照其不同的属性传入不同的电梯线程。指令的捎带判断放在了请求队列类里,因为一个指令最多需要两个电梯就能执行完,因此在请求队列里判断得到,一个指令由一个还是两个电梯执行,以及怎么执行。剩下的基本与第六次作业相似。
本次作业的设计的优点是,指令由哪个电梯执行的判断简单直接。缺点是,指令的调度策略会很差。
度量分析:
Metrics图中显示,Ele类和Scheduler类的run的代码块依然嵌套过深。Ele类,则因为每个电梯线程的电梯编号,上升或下降的时间,最大载客量等属性需要传入,使得其参数数量过多。Line类的addline方法,因为需要对9种电梯指令分配情况进行判断,不断地使用if-else语句,使得其圈复杂度过高。ELe类的getin方法,判断是否在当前楼层开门并捎带,因为限制了最大载客量,需要对当前的电梯人数,主请求,当前楼层的请求等综合判断后,才能决定是否在当前楼层开门捎带,因此圈复杂度过高。Scheduler类的comput方法,则因为其需要判断当前指令队列是否有可以调度的指令,以及将该指令给哪个电梯,因此圈复杂度过高。
(2)分析自己程序的bug
因为第六次作业的不断地解决BUG,因此本次作业在其基础上扩展,并未被发现BUG。
(3)分析自己发现别人程序bug所采用的策略
依然是通过观看别人代码的方式,但并未发现BUG。
SOLID原则分析:
单一职责原则(SRP):每个类专注于单一明确的功能。
开放封闭原则(OCP):基本满足。
里氏替换原则(LSP):没有子类设计。
接口分离原则(ISP):没有接口设计。
依赖倒置原则(DIP):没有抽象类设计。
心得体会
(1)在考虑和设计线程之间的交互时,需要明确当前线程的职责,然后明确交互线程之间在哪些数据之间形成了交互,这些数据是否可能会发生冲突,是否需要加锁。
(2)访问控制都是在线程类代码中实现的,下一步将学习如何在共享对象中实现。
(3)加锁的时候,依然是锁住整个对象,如何只锁住关键部分就能达到效果,是下一步需要不断探索解决的问题。