OO第四单元UML作业总结暨OO课程总结

目录

一、第四单元UML两次作业架构设计

第一次作业

  第一次UML作业的文件树如下:

tree_1.png

  本次作业采用的是分离需求的设计思路,每一类需求整合到对应的类中单独存储,并配置修改和访问方法。

  在顶层,实现课程组提供的UmlInteraction接口的类MyUmlInteraction只负责将UmlElement传入parser解析,并对外提供查询接口,剩下处理数据的任务交由parser完成。此外,在此类中还存放有所有UmlElement的查询表,并提供全局访问方法,通过id即可访问到对应元素

  MyUmlClassMapParser类负责解析处理类图中的UmlElement,考虑到后续作业会新增顺序图和状态图的解析,故将其放在parser包中以便扩展。

  ClassBlock类存放了需要查询的类/接口中的信息(名字取的不好。。把接口和类统称为类块了),其中包括:AssociationInfo(关联信息),AttributeInfo(属性信息),InterfaceInfo(接口信息),OperationInfo(方法信息),这4个需求信息统一归到infos包中管理。

  对于用于查询的各个info类,存放信息使用的数据结构基本上为HashMapHashSet嵌套使用,且在每个info类中都或者存放有已查询过的confirmed数据表,或者是isConfirmed的boolean型确认表,其目的都是为了实现记忆式查询,如属性可见性、关联对端等需求的查询,在访问过父类后即可记录下结果,下次访问时就不必再重新往深层探索,而是直接获取已有数据,这样就使得查询的速度会随查询次数的增大而加速。查询方法采用的算法基本为递归查询,以便在回溯时记录数据。

  以下是本次作业的Uml类图:

overview_1

package_blockandinfos_1.png

package_interaction...dparser_1.png

第二次作业

  第二次UML作业文件树如下:

tree_2

  本次作业大部分继承了上次作业采用的架构,改动的地方是除去了parse包,而将每种UML图的解析都归类到单独的包里,即classmap包(负责类图处理),collaration包(负责顺序图处理),statechart包(负责状态图处理),并将各个parser放在了对应包的顶层。此外,新增的checker包用于归类UML规则检查。

  类图的处理在第一次作业中已经介绍,在此不再赘述。顺序图的处理按照UML顺序图的分层方法进行了层次划分,Interaction类作为“画布”存储了核心的解析数据,如lifeline,message等(顺序图的画布Interaction“撞脸“了解析器的命名,所以在命名这一环节上处理得不太好),MyUmlCollarationParser提供解析数据与查询数据的接口。类似地,状态图的处理也按照UML状态图的分层方式进行层次划分,Region作为”画布“存储核心数据,MyUmlStateChartParser提供parser功能。

  本次的checker包中只有一个MyUmlChecker类负责规则检查,一方面是为了方便,另一方面也是作为UML类图规则检查划分到一个类中。如果后续有扩展需求的话,可以选择在类中添加方法或建立新的类,按照检查的维度进行划分。

  以下是本次作业的Uml类图(与第一次作业相同的内容省略):

overview_2

package_collaration...techart_2.png

package_checker_2.png

二、架构设计总结与OO方法理解演进

  • 第一单元:表达式求导

  作为OO的最初篇章,脑子里对“架构”这两个字并没有什么概念,对于程序的设计仍停留在分析需求、面向过程的编程思想上。当然,对类和对象概念的理解也促使着我在朝着面向对象的思维方式上转变。

  这一单元的三次作业采用了三种不同的架构设计,但设计的思想都大抵一致,也就是将表达式逐层剖离至基本元,再进行求导。第一次作业只分离出了Unit作为最基本的求导元,没有考虑可扩展性,是为完成需求而设计,利用正则表达式对表达式进行拆分解析的过程也统一放在Expression类中。第二次作业的需求直接报废了第一次作业的设计,虽然仍是用Unit作为基本元,但对这一基本元类做了重构,将其修改为三元组(x, sinx, cosx)的形式进行存储,本次作业做了一个新的尝试是将求导操作抽象为一个类,在计算时实例化求导对象进行计算。第三次作业的需求又再次颠覆了第二次作业的设计:三元组无法支持嵌套元求导,故又再次进行了重构,将表达式解离为多个嵌套表达式,而嵌套表达式又由多个基本表达式和嵌套表达式组合而成,并尝试抽象出了CombTermTerm两个接口以显示自己有在学面向对象,当层次设计完成后,表达式拆分的目的地就比较明确了,求导计算就变成了自顶向下逐层完成任务的过程。

  总之,第一单元的体会就是:次次重构次次爽。虽说这一单元花在表达式解析和WF判断上的精力比较多,但其实面向对象的思想也有训练到,尤其是第三次作业,在设计好层次关系,理清各个层的职能之后,真实地感受到思路清晰带来的爽快感。

 

  • 第二单元:电梯调度

  这一单元亲自体会到了多线程的“恶心”之处,但实际上在完成这一单元的训练之后,会发现在一开始架构设计的大路就已经被课程组铺好了,剩下的只是怎么在这条路上走出花样、走出水平。作为多线程和设计模式的零基础学员,只能老老实实按部就班地“走大道”了。但不得不说的是,接触了设计模式与设计原则后,已经逐渐能够从面向过程的需求分析思维,过渡到面向对象的架构设计思维上去了。

  第一次作业十分简单,老实按生产者-消费者模式代入即可安全通过。第二次作业加上了捎带的需求,仍然沿用生产者-消费者模式,改进的地方是引入缓冲区供捎带队列的获取,以及电梯内的捎带算法调整,感觉这次作业自己的重点更多地放在调度策略的设计上,而对架构的考虑不是很充分。第三次作业使用了Worker-Thread加观察者的组合模式,即电梯作为工人获取请求并处理,调度器存储外部请求,并可以登记或移除电梯。对于换乘的设计,采用“换乘港口”的思路,将请求送至港口后就作为新请求送入调度器。

  这一单元对设计模式的了解使得架构设计在一定程度上变清晰了(虽然内部调度处理还是让代码变得很难看。。。)。对SOLID设计原则的考虑也进一步规整了设计,而不仅仅停留在“完成需求”的要求上了。

 

  • 第三单元:JML规格语言

  这一单元的训练重点是JML规格语言的理解和代码功能的迭代设计(其实我感觉重点更偏向图论和数据结构。。。)。不过令我满意的一点是,这三次作业的重构范围比较小,基本上是在沿用上一次代码的基础上根据需求进行增添,这或许是能力提升的一个表现?

  第一次作业没有创新,只实现了官方的接口就能通关。第二次作业在实现接口的基础上增加了MyGraphCalc类用于处理图的相关计算。第三次作业按照功能将类划分入了三个包,即calculator,container和raildata包,分别代表计算模块、顶层容器模块和地铁系统中相关数据模块。计算模块负责图结构或地铁系统中的相关计算;顶层容器模块负责提供路径、图、地铁系统的修改与访问接口;地铁系统中相关数据模块将地铁系统中需要查询的信息分为几个模块(连通块、最少票价、最少不满意度等),每个模块中完成指定信息的修改、存储与访问接口的提供。

  总的来说,这一单元算是复习了一遍数据结构和图论,但不知不觉地,自己也对架构的设计有了要求,并且这是一个良性的过程,设计考虑得越周到,编码消耗的时间就越少,bug也容易定位。

 

  • 第四单元:UML图解析

  这一单元的架构设计已经介绍,故不再赘述。从第一单元的设计尝试,到第四单元认真地思考哪一种设计能更好地实现需求,并且对可扩展性、耦合度、鲁棒性都有一定的考量,对架构设计的理解算是有些小进步吧。但要想设计出优秀的架构,现在的能力还相差甚远,还需进一步在练习中不断学习。

 

三、测试理解与实践演进

  测试确实是软件设计中不可或缺的一个环节,每次作业看到中弱测全过时,内心就会产生一种错觉:我的程序已经没有bug了!然而强测一片红时又会开始悔不当初:为什么当初不好好做测试?在一学期四个单元里,测试方法由肉眼法到写对拍器,再到Junit测试,算是测试实践的逐步演进。每次经过充分测试后,心里就会十分踏实了,而如果再被纠出bug,这些bug就不再是粗心大意导致的bug,而成为值得回顾反思的“优质bug”。

  第一单元对测试不是很上心,测试的方法是比较原始的肉眼查bug,无论是对自己的程序还是互测屋中的程序,测试的精力放在输入输出的检测上,对于求导的逻辑就没有过多的关心。在第三次作业时实现了对拍器,算是测试方法的一种改进,但实际上有了对拍器后就更懒得看代码了。。。研讨课上同学分享的观点值得反思:“互测的目的并不是‘找到’,而是‘去找’。“

  第二单元的电梯作业,由于是多线程设计,测试起来就更加困难了,在自己的程序测试中采用的是IDEA中自带多线程Debug方法。在互测屋的测试中实现了定点投放数据脚本,但没有实现对拍器和数据生成器,因此只能以肉眼观察找数据为主,定点投放为辅,配合使用进行测试。

  第三单元真正接触了Junit,体验极佳!尤其是看到代码覆盖率和自己代码栏左侧密集的绿条时,内心十分满足安心。此外,写完Junit测试程序后,每次测试只需一键,非常方便,可以轻松定位到bug出现的位置,即使找到逻辑错误,进行一定范围的修改后,也一键测试也很方便检测此次修复的bug是否会影响到之前测试点的通过率,避免出现“修复1个bug长出10个”的情况。

  第三单元还接触了JML规格检查以及JMLUnitng自动生成测试样例等JML有关的测试方法,这些方法虽然在理论上十分强大,但目前好像并不是很“智能”,期待以后的发展。

  第四单元的测试仍沿用Junit的测试方法,但发现写Junit测试程序也需要耗费一定的精力,尤其是在课程组提供官方接口的情况下,测试样例的编写就比较困难,也许是我还没有发现样例编写的捷径?

  总之,在测试方面也算是有了些收获,也意识到了测试的重要性,日后还需要在这方面上下足功夫。

四、课程收获总结

  本学期对于OO的训练量,说多也不多,说少也不少。不多的原因是独立设计出的架构还远没有达到OO所要求的质量,不少的原因是这学期确实在摸爬滚打中走来,也有了不少“自己的东西”。

  从各个单元实际内容的收获来看,第一单元学到的是正则表达式解析表达式与表达式的处理,第二单元是多线程程序设计与电梯调度,第三单元是JML规格语法与图论,第四单元是UML模型的理解。通过对各种问题的分析,以及阶梯式的问题难度和测试,对于各类程序设计问题都有得到一定的训练。

  从各个单元的设计目标来看,虽然没有完全达到目标,但在接近目标的过程中也有不小的收获。第一单元的目标是 “构造抽象层次,进行归一化处理“,在将表达式逐层解析的过程中,也在锻炼将问题抽象分解的能力。第二单元的目标是 ”识别线程及共享数据,控制共享安全“,由于初次接触线程安全,即使经过三次难度递增的作业的训练,对线程安全的理解还只停留在比较基础的阶段,对一些线程控制方法并不能很好的融汇贯通,不过能够完成协调多个线程工作的任务,也算是一大收获吧。此外,设计模式的学习也提供了架构设计的模板,这些模板并不一定要生搬硬套,理解这些设计模式后相信对自己的设计能力会有很大帮助。第三单元的目标是 “根据功能需要适应性能要求的中间数据模型和协同架构”,第三单元虽说是以JML规格语言为主题,关注的重点更多的是如何让自己的图结构算法不被RTE,三次作业依次地逐层构造以及复杂度的增加,对架构设计的可延续性与性能的考虑能力有所提升。第四单元的设计目标是 “针对诸多不同类型的对象构造层次和关系,构造模型过程中动态维护相关查询数据”,这一单元给出了各个对象原型,训练的是如何将这些对象按照其属性特征、功能结构进行分层、整合,从而更好地协同工作。

  总体来看,这一学期收获到的是面向对象程序设计思维与架构设计能力的入门卡。不得不说,一个好的设计架构所带来的编码体验是不言而喻的,体验到架构设计的魔力以后,未来对一份需求的设计就会更加上心,运用合理的架构设计思维去分析需求所获得的效果。以及,课程收获到的还是强大的抗压能力:中测wa掉一个不可见的点无论怎样都测不过,即使心态爆炸也要含泪继续debug;在有限的ddl之前如果架构崩坏,需要有狠下心重构的勇气;强测爆炸即使很沮丧仍要笑对bug修复。。。

 

五、课程改进建议

  1. 指导书对需求的规定需要有一个时间点完全定格下来,否则的话规则的任意修改不利于提早动工的同学,容易引战。
  2. 当程序代码量和复杂度增大时,互测屋的积极性可能会有所下降(尤其是我这种懒人。。。),虽然有着活跃度惩罚的威胁和优秀代码的吸引,但有时候实在没有认真翻阅8个人代码的动力。因此,课程组可以根据强测的结果,给出几个互测中的关注重点,这些重点虽然一定程度上降低了互测的难度,但同时增加了查看代码的效率与积极性,而不会出现看了几遍别人的代码逻辑毫无收获的情况。此外,互测关注重点还可以引入单元中的重点,从而让同学们在翻阅代码的过程中不断回忆单元重点内容,巩固提高。
  3. 课程网站中将BUG修复的修复情况可以整理放在个人中心里面,而不是在BUG修复结束后只有”Bug修复已结束“几个字。。。这样在单元结束或学期结束还可以回味一番,总结踩过的坑点的同时还挺有乐趣:-) 虽说这些bug总结工作可以私下在本地完成,但是有时由于时间原因或是其他原因也会导致这项工作不能很好地得到完成。总之,有个平台能够帮忙统计是一件提高学习积极性的事情呀!

 

六、尾声🎉

  感谢老师、助教、讨论区大佬们这学期的帮助与贡献!祝愿OO课程越办越好🎈🎈🎈(这学期体验其实挺不错

posted @ 2019-06-24 11:00  kingkongk  阅读(220)  评论(1编辑  收藏  举报