OO第二次总结

  第二次OO总结如下。

  作业一共分为三次,分别是一次电梯,一次IFFF,一次出租车调度。分析顺序是从后往前。

  

一、出租车调度

    程序输入为具有固定格式的命令,系统解析当前的命令,按照当前出租车的实际情况来分配合适的车辆,输出是每次调度的具体细节。

    有了上次电梯的调度经验和对IFFF多线程的理解,这次作业写起来稍微有娴熟一些,设计和处理每一个模块之间的关系用了一天的时间,然后就是不断的填充细节。在设计上:

   1.设计原则真的是很有用,这次的Main函数只是作为一个入口,包括输入处理系统,装换系统,调度系统,输出处理系统都做了比较清晰的分割,耦合度也不是很高。

    2.在线程安全上,还是借鉴了老师讲的托盘以及线程锁。相比之下托盘系统真就像是一个用来盛放所有线程的“托盘”一样,并且提供了每一个线程所需要的共享资源。这次作业的“托盘”就是Scheduler类,托盘不是线程类:托盘包含输入处理装换系统和一个和调度线程的接口,这个接口主要是将合法的输入命令和一必要的共享资源作为参数的命令执行线程(一般即使出租车调度系统的执行体)。

   下面是UML类图:

可以从上图中看到,这次的逻辑相比较前几次来讲也是比较清楚的。主体还是Dispatch、taxi、request三个多线程类。

时序图:

    3.整体上看,主要协同的线程有三个:调度线程——出租车线程——订单线程。这三个线程之间的关系是递进的关系,因为第一次的功能也比较单一所以从收到命令,到出租车开始调度,然后确定出租车线程开始启动到确定订单参数到输出订单也很明了。唯一的线程安全就是在调度系统中100辆出租车的状态(设计中每一辆出租车对应一个订单)。

    4.线程安全的角度来分析的话,会发现出租车的状态在每一条输入开始触发调度的时候都需要实时更新,并且随时有可能被不同的调度线程改变,所以需要上锁,不知道为什么从第三次电梯作业之后我就没有使用过notify和wait函数处理过相关的线程安全问题。可能是对多线程和线程安全的理解还不够透彻吧。

    5.最后就是代码规范的问题,推荐一个插件Alibaba Java Coding Guidelines。这个插件提供静态代码规范检查,对初学者很友好。

复杂度分析:

   可以看到,这次的作业在taxi和调度上复杂度是有一些高的,而且主要在所有的关于判断的函数——比如isSame()用来判断同质请求,FilterTaxi()用来判断正确的指令等这些的可维护性ev(G)都不是很好,我想可能是因为这些代码中硬编码的部分比较厉害,因为要针对每一个命令,或者出租车的具体属性和状态来进行判断,所以如果taxi和request有所改动,那么这几个函数一定是要跟着变的。修改方式可以是:在写一个类作为托盘,将该taxi或者命令有需要判断的属性或者状态都放在该类中,在判断类里只需要调用这个类就可以。

  个人觉得v(G)指的是耦合度吧,可以看到我的代码中这个指标最高的就是FiterTaxi()函数了。

  后来看了一下测试任务中的大佬代码,发现设计的很厉害了,见下。

  6.关于测试

  这次的大佬看起来是深谙设计原则,对于类与类之间的关系,线程安全的处理都比我好太多;

  在设计层面,他将出租车线程和出租车的具体实现方法分离,我觉得这是一个很好的处理方式,因为从设计原则角度来讲:这样符合开放封闭原则,因为如果想进一步对出租车的功能进行扩展,就不会再殃及到其他使用到出租车功能的类了,因为和出租车有关的所有函数以及属性都被封装在taxiThread中。符合“低耦合,高聚合”。  

  测试程序对地图上的点做了封装,对输出信息做了分装。并因为每一个类有自己单独的属性所以在处理线程安全问题上很清楚明了。看来这位大佬深谙面向对象的精髓啊,相比之下我感觉还是面向过程一些,虽然逃离了按部就班的思考,但是在对象的属性以及dependicy上还是很有欠缺的。

  7.BUG

  我的BUG主要是在最短路径算法上,最后直接是用计算的方式进行输出,而并没有按照最短路径的方式来做,所以输出这块还有很大的缺陷导致GUI也是失效的。

  大佬嘛,就没有了。

 

二、IFFF文件处理  

  在这次作业中,我也算是真正的明白了关于多线程和线程安全的一些知识。

  先上图:

 

  1.电梯调度的失败警醒我一定要多交流,多看优秀的代码。

  在最后一次电梯作业中,一位大佬的代码对我启发很大,所以这次作业完成的稍微好一些。主要问题处在目录操作上,并没有对目录文件进行操作导致出现和目录相关的7个BUG,但是在看到别人代码的过程中我也领悟了如何构建更好的代码——比如多使用重构,重新实现equals()函数以及clone()等函数,尽量降低耦合度,养成先分析在写代码的好习惯。。

     

  这次代码中一个很大的进步就是学会了使用继承来处理一些类与类之间的关系,比如说四个基本的文件操作都是继承父类的,还有响应类型也是继承的手段。还有就是在使用线程安全的时候多想想如何才能尽可能的避免不必要的线程安全问题发生。

 

   2.从图中可以看出,基本上复杂度和耦合度,可维护性最高的地方都很集中的分布在文件处理,我觉得和出租车一样吧主要还是这写方法和函数用到很多关于对象本身类的属性,所以和处理的对象类耦合度是很高的,这一点应该避免。

  3.BUG

  主要是在文件目录操作上没有时间去写了,所以有7个BUG都是和目录相关的,但是代码中目录操作和文件操作耦合度很低,并且都是单独的处理线程,所以一般来讲只是加上了一个新的功能。不过估计没有时间再去补充了。。。

  还有一个比较重要的就是输出文件重定向的问题,正确的应该是使用Fwrite();函数,但是我直接将System.out.println()函数的输出位置变了一下,这样的话最终的结果就是第一个线程在输出重定向之后,第二个线程所有的输出也会被重定向,但是我在控制台还有一些debug信息作为辅助一并都输出到源文件中了。。这就很尴尬。

 

三、终极电梯

  虽然电梯作业从一开始就一直很被动,自己没有更上节奏。一直不想去想这次作业,,不过DDL是第一生产力所以还是大体回顾一下吧。

  1.没有搞懂电梯多线程的用法。

  2.没有处理好前两次电梯类的BUG。

  虽然最后的作业是因为没有被测试然后过了,但是心里还是很不爽的。因为我实际上只是处理了非法输入的部分,要是按照当时的标准是要被判无效的。

  大难不死必能学会一些东西,我开始极度重视issue,并主动在issue上提问,结果发现真的很有用,很多同学都说一直等到周一晚上再看一下issue就会避免很多坑,但我想说的是其实你避免的不仅是坑更是讨论过程中思想的碰撞和理解力的训练。我个人是觉得讨论过程其实更是一个理解的过程,有时候一个功能需要理解好多次才能避免掉语言的陷阱,好多次就意味着需要时间来沉淀这些理解,可能是我太菜所以理解问题的时间间隔比较长吧,不过就算很强,还是能通过这种训练提高你的表述能力(问问题)和理解能力(看懂别人的解释)。

  

 四、总结与体会

   这三次作业相比上三次稍微好了一些,OO教会我题意都没理解就死了是一种什么心态。不过更多的是发现交流的重要性以及自身对时间、专业细节的把握,不得不说价值真的很高。

  从线程安全的角度来讲,这几次作业因为都是多线程所以肯定或有一些线程安全的问题,但是综上来看一般共享对象也不是很复杂,所以处理安全问题并没有花费我太多的时间,不知道是自己的理解有偏差还是代价都这样。

  设计原则方面,由于是代码量开始接近1000行,所以维护的重要性慢慢的开始体现。尤其是要批量修改文件的时候,必须得知道自己哪里没改,设计原则给了我一个很好的地图就是我知道能去哪里修改我的代码,但是主要还是自己不够强,所以在时间有限的情况下要顾及方方面面真的很累,不过我觉得适应就好,像代码风格和设计原则这些都应该是过程中一步步养成的好习惯吧。

 

五、Mac下IDEA使用PlantUML来作时序图

  第一步:下载插件PlantUML(需FQ)

  百度网盘:链接:https://pan.baidu.com/s/1ZG7QuIzOZZpWHMIjvJ2lOQ  密码:0s3s

  第二部:下载Graphviz来支持图形界面

  max直接用brew下载:    

brew install libtool
brew link libtool
brew install graphviz
brew link --overwrite graphviz

 

  第三步:在项目src目录下右键运行插件

  

  第四步:界面有点类似Markdown编辑的方式,通过写代码来建模:

  语法可以查看官网上相关的介绍:Plantuml.com

  第五步:主要使用到的就是participatant和箭头,参考下图即可:

  

  

    

posted @ 2018-05-02 11:06  HaotianMichael  阅读(259)  评论(0编辑  收藏  举报