OO博客做业2:第5-7周做业总结

(1)从多线程的协同和同步控制方面,分析和总结本身三次做业来的设计策略及其变化。java

第5次做业:多线程电梯算法

基本照搬了课件上“生产者-消费者”模型的设计策略,将InputHandler设计为生产者线程,将Scheduler设计为消费者线程,将RequestQueue设计为托盘。生产者与消费者的工做并发,提升效率。同时,每部电梯设计为一个线程,由于每部电梯的运行彼此不干扰。InputHandler, Scheduler由主线程建立,三部电梯由Scheduler负责建立,这样使得调度器能够获取电梯的状态。但这种策略并非最优的。编程

第6次做业:文件监控缓存

这大概是写得最失败的一次做业。安全

按课件方法构建了线程安全的SafeFile类。实现了同步化的访问文件状态、写文件方法。然而对于每一个record型请求单独建一个文件写入,违背了训练初衷。多线程

每一个请求设计一个“监控器”线程,直接查看对应文件的状态,与指导书的设计思路差别较大。这使得程序难以应对path-changed等大规模变化。并发

总的来讲,此次多线程之间没什么协同可言。同步控制也仅限于对文件状态的访问。eclipse

第7次做业:出租车调度测试

此次做业的设计策略基本照搬第5次做业。输入处理线程为生产者,调度器线程为消费者,请求队列为托盘。每辆出租车为一个线程,依然由调度器建立。线程

写了线程安全的SafeFile类用于输出文本文件。乘客请求、参与抢单的出租车信息由调度器负责写入,出租车运行状况由出租车线程负责写入,实现了线程协同。

 

(2)基于度量来分析本身的程序结构

1)OO程序代码度量

第5次做业:

类名 属性个数 方法个数 代码规模 main / run方法规模 点评
Elevate_5 0 1 27 17  
Elevator 14 7 176 40 电梯控制逻辑复杂。
Floors 2 4 24    
InputHandler 10 6 158 15 写得太随意,不少属性更适合做为局部变量。
Request 4   59    
 -CarryRequest 1 3      
 -FloorRequest 1 3      
RequestQueue 6 4 56    
Scheduler 7 8 209 40 保留了上次的调度器代码。
Tray 3 4 76    

第6次做业:

类名 属性个数 方法个数 代码规模 main / run方法规模 点评
Detail 4 3 64    
FileState 4 3 26    
InputHandler 9 6 107   类似的问题
Monitor 8 2 60 30  
SafeFile 2 15 110   为测试者写了较多的方法
Summary 4 3 64    
TestDrive 0 1 15    
TestThread          
Trigger 3 8 94   设计有问题

第7次做业:

类名 属性个数 方法个数 代码规模 main / run方法规模 点评
_Point 2 7 40    
CHandler 9 4 76 32  
CityMap 4 4 114   算法代码比较长
FHandler 2 4 55    
Queue 3 3 49    
Request 3 3 24    
SafeFile 2 5 57    
Schedule 6 6 146 44 调度方法夹杂输出代码
Taxi 16 9 204 40 运行方法夹杂大量输出代码
TestDrive 0 1 18 12  

3)各次做业的类图

第5次做业:因为指导书给出了上次电梯的参考类图,本身的设计基本遵循了指导书。可是Tray这个类没能发挥出应有的做用,只是单纯地缓存请求。更好的作法是同时缓存电梯状态,电梯运行时更新,调度器须要时读取。

第6次做业:写得很糟糕,有“面条代码”的嫌疑。对Monitor和Trigger两个类的职责没有明确,并且Summary和Detail的代码有大量重用。

第7次做业:不少地方参考借鉴了第5次做业(多线程电梯)。各个类的职责相对清晰。

4)UML的协做图(从上到下依次是第5,6,7次做业的图)

5)设计原则检查(仅针对第7次做业)

DIP (Dependency Inversion Principle):高层次不依赖低层次。

程序有两个渠道获取输入,一是经过文本文件获取城市地图,二是经过控制台获取叫车请求。个人程序没有将这两种途径进行抽象和概括,致使程序对输入方式变化的适应性很差。

命名:

在为类、实例变量命名时我尽量遵循“顾名思义”,可是走向了另外一个极端。我将一个记录点信息的类命名为“Point”,结果后来发现有java.awt.Point这个类,使用GUI时很不方便。无奈之下我将本身写的类更名为“_Point”,花了一部分时间更名字。在顾名思义的同时,也尽可能不要取过于简单、大众化的名字,不然容易与JAVA类库重名,形成麻烦。

另外,eclipse建议包名首字母小写,类名首字母大写,做为初学者仍是遵照得好。

 

(3)分析本身程序的bug

第5次做业:

全部的“正确请求测试多线程功能”样例均有错(公测未发现或是被发现bug)。

问题所在的类是Scheduler。

被发现了一个CRASH是因为想向文件写入结果,但文件已经关闭致使的。这暴露出我对于多线程同步控制还没有掌握,且本身构造的测试样例太宽松,很容易露出破绽。

从设计结构角度分析,我把全部的电梯调度方法全写入一个调度器类。Scheduler类的代码规模更是破了200行,远远超过其它类。

在总结课上,我才了解到有更加均衡的实现方式。总调度器只负责将请求分配给不一样的电梯,而每部电梯对应一个专门的调度器负责排请求的执行前后顺序。这种方式显然更合适,既是遵循均衡原则,又符合实际的应用场景。

第6次做业:

对方没有进行公测,且没有发现bug,故不做分析。

第7次做业:

被发现了一个bug,为新增节点“等待状态下出租车的运行不具有随机性”。

问题所在的类为Taxi,方法为run_edge

这个bug被发如今情理之中,由于我曾经尝试过实现出租车的随机运行,可是失败了(出租车发生了瞬移)。最终改为了一版肯定性运行的方法。

(4)分析本身发现别人程序bug所采用的策略

不少学生(包括我)在编写多线程程序时遇到的一个技术难点就是如何让程序正常结束(在eclipse下是在控制台上方看到<terminated>)。尽管这不是指导书的硬性要求,可是可以正常结束的程序势必带来更好的用户体验和更强的鲁棒性。若是被测者没有在readme中对程序的结束进行说明,或是说明能结束但实际上没实现的,则能够报告bug。

边界条件是在编程过程当中须要着重考虑的。一些在实际状况中彻底有可能出现,但编程者很难考虑到的测试点上每每容易发现bug。第7次做业我经过构造“乘客请求起始坐标正好是出租车所在位置”的样例,成功发现了别人的bug。

后期的做业不但注重程序正确性,并且对程序设计原则也提出了要求。测试者能够阅读被测代码,发现其中不符合设计要求的部分,予以扣分。

 

(5)心得体会

1)线程安全

在线程安全方面,重点是把握课上重点讲过的“生产者-消费者”模型,学会将共享对象的存取方法设置为同步化的,以及方法内部具体的写法。拿到指导书以后,在分析程序须要哪些对象、对象之间关系时,必须额外考虑哪些对象须要被共享的问题。不管是本身写被共享类的代码,仍是包装为线程安全类,都要想清楚哪些方法须要保证原子性,并使用synchronized关键字。

2)设计原则

从第7讲开始,课后做业将程序设计原则也归入了做业要求和互评范围。设计原则与程序的正确性没有直接的关系,而是为了让程序具备较好的可读性、可扩展性。在软件开发行业,用户需求发生变动是常常遇到的事件。遵循课上讲过的一些设计原则能够加强程序的可扩展性。在需求变动时,只须要对原有程序进行有限的修改,而不是推倒重来。本身在3次电梯做业中,后面的做业每每不能有效利用前面做业的代码,缘由在于本身没有在一开始构造一个良好的设计,没有遵循设计原则。另外一些原则是为了程序可读性,由于未来咱们开发的程序只是一个大项目的一部分。不但要保证别人放心调用,并且最好在代码中清楚写出本身的逻辑。可能通过后面几回做业的训练,我可以更深刻地理解设计原则。

相关文章
相关标签/搜索