OO第二单元总结

一、三次作业设计策略:

  1.第一次作业:

    

    第一次电梯作业,用了较为麻烦的方法,即采用五条线程去完成电梯任务,分别是ElevatorThread : 主电梯线程,进行电梯各种行为,并输出(包括上下行,开关门)。EleObserverIn、EleObserverOut : 负责检查电梯是否处于开关门状态,若是,则调用Store中的getin、getout方法使人产生进出电梯行为。InputThread : 根据输入生产人的实例,并将其存入Store中。Main线程 :创造各类线程。

    解决这次作业的主要采用了生产者-消费者模式,由InputThread线程生产,EleObserverIn线程消费,同时EleObserverIn又作为EleObserverOut的生产者,有两个托盘,一个是noinlist,负责装载未进入电梯且未使用电梯的人,另一个为inlist,负责装载进入电梯的人。至于EleObserverIn和EleObserverOut,二者并未实现观察者接口,严格意义上来说不算是观察者,但确实采用了一些观察者当中的思想,即根据被观察者某个状态的改变来决定观察者的行为。

  2.第二次作业:

    

    第二次作业在第一次作业的基础上,去掉了Store中的noinlist和inlist,将两个列表移入Elevator中,即每个电梯都有属于自己的消费域。同时将作业一的两个观察者合为一个观察者,减少了线程数量。在其他的设计方面,就基本沿用了作业一的策略。

  3.第三次作业:

    

    第三次作业在第二次作业的基础上,通过继承,分别编写了ElevatorThread的子类A,B,C,同时在Store中添加了三个电梯列表用于储存不同种类电梯,并为动态的添加电梯增加了elevadd方法。关于换乘问题,提供的解决方案是对Person类进行修改,添加canin布尔变量表明该人是否可以进入电梯,且在存入Person实例时,若其需要换乘,则根据某种策略,修改其目的地使其可用A、B、C其中任一电梯不用换乘就可到达,同时再生成一个新的Person类,置canin为false,将二者关联起来,新的Person类也可通过A、B、C任意电梯不经换乘就到达目的地,但其canin变量必须等到另一人到达目的地后在修改为ture。

    三次作业的调度策略都为scan算法。

二、第三次作业架构设计的可拓展性:

  SRP原则:每个类或方法都只有一个明确的职责。

    在第三次作业中,run方法过于冗长,没有很好的满足该条件。

  OCP原则:无需修改已有实现(close),而是通过扩展来增加新功能(open)

    若还有第四次作业,根据前两次的情况来看仍必须小幅修改已有设计,并在已有设计上进行拓展,所以对于该原则,基本上没有满足。

  LSP原则:任何父类出现的地方都可以使用子类来代替,并不会导致使用相应类的 程序出现错误。

    第三次作业第一次用上了继承关系,就实际操作来看,本人在程序建立的大多父类,都是根据子类行为来不停的修改父类行为,该条原则能够很好的满足。

  ISP原则:使用多个隔离的接口,比使用单个接口要好。降低类之间的耦合度。

    在第三次的作业中,类与类之间的耦合较为常见,其中Store与ElevatorThread有关,ElevatorThread与Penson相关,在设计之初已经尽量避免了类与类之间耦合,但为了程序在某些地方可以写的更加简洁,还是无法避免的增加了类之间的耦合程度。

  DIP原则:高层模块不应该依赖于底层模块,两者都应该依赖于其抽象

    关于模块层次部分,在设计的第三次作业中未有太多体现,但若可把父类视为高层模块,其实在LSP原则中就可看出设计并未很好的满足DIP原则。

三、基于度量分析自己的程序结构:

  1、第一次作业:

    

    第一次作业,写了五条线程,一旦电梯数增加,线程数会大幅增加,增加编程者负担。

    

    

    

    从上图易看出getin,getout,以及ElevatorThread中的run()方法过于复杂。

  2、第二次作业:

    

    第二次作业在第一次作业的基础上,将两个观察者合为一个,减少了线程数量,降低了之后的编程难度。

    

    

    结论同一,但因将ObserveIn和ObserveOut合并,使得部分简化了getout,getin方法。

  3、第三次作业:

    

    第三次作业类图庞大,逻辑复杂度上却并未比第二次作业增加太多,得益于给每个电梯分配了不同的消费区,但却也在一定程度上降低了效率。

    

    

    总的来看,第三次作业代码复杂度从平均值上去看,并没有比第二次作业高出多少,甚至还有些部分低于第二次,当然,这些数据都是依赖于简化调度策略而得到的。

四、分析自己程序的BUG:

  由于在这三次作业中,只用了一把锁,所以死锁错误基本没有出现,就算出现也并不典型且不具有探讨意义,故忽略。其他情况,一次算法错误,导致电梯运行超时。另一次是在线程中采用了随机算法,导致其与线程的不确定性结合,有时候能跑出正确结果,有时候不能,后来对该算法进行一定更改,修复了BUG。

五、发现别人BUG所采用的策略:

  把别人的输入线程替换掉,使用随机生成数据并可定时线程代替其输入线程,再在外部写一个结果分析的python程序,手工复杂粘贴,然后让python程序分析。(如出现死锁情况,在一旁观察就很容易发现(人工测评。))

六、心得体会:

  相比于自己第一单元每次都重写代码,这一单元的情况就好了很多。第二次作业只在第一次作业上修改了一点就完成了要求,而第三次作业,也未有太大的改动就成功完成了要求。而且代码风格的约束(特别是60行代码的约束),通过上一单元的教训,突然就了解了为什么要有这样的约束。之所以将每块代码控制在某行数内,是为了方便阅读者(无论是开发人员还是其他人员)更快了解该代码块的作用,从而得到更好的编程体验。

posted @ 2020-04-17 17:43  1216  阅读(110)  评论(0编辑  收藏  举报