OO第四单元总结+学期总结
一、第四单元作业架构
1.第13次作业
本次作业要求进行对UML类图的解析、查询。
由于官方包中的UmlXXXX类无法方便地记录元素间的层次关系,以及一些额外信息,所以采用对象适配器模式,为每一个UmlXXXX类建立对应的MyXXXX类,添加我需要的属性和方法,建立起UML类图中各元素的层次关系。
在UML中,类和接口都可以继承、实现、关联,所以用Generation、Realization、Association三个接口来规范继承、实现、关联的相关方法,并使MyClass类和MyInterface类实现这三个接口。
这次不好的地方是,在总的管理类中,用四个HashMap存了id到类、id到接口、id到方法、id到关联的映射,但其实可以分层地管理,比如方法归它所属的类管。
Cache类是在执行需要搜索(耗时较长)的方法时,如果输入的参数和之前一样,就直接返回结果,不用再搜索一遍了。是为了提升一定速度。
2.第14次作业
本次作业加入了顺序图和状态图的解析与查询。
顺序图和状态图的元素采用了分层的管理,结构较为清晰简洁(从上面类图就能看出来)。
MyUmlGeneralInteraction中维护了ClassManager、InteractionManager和StateManager,分别用于处理类图、顺序图、状态图的请求。MyUmlGeneralInteraction负责请求的分配。
3.第15次作业
第十五次作业加入了对类图、顺序图、状态图的有效性检查。
Graph类负责对整个类图做深搜。加了Node接口,MyClass和MyInterface在Graph类眼中都是Node。
加了MyClassOrInterface接口,继承Node、Generation、Realization、Association四个接口,并使MyClass类和MyInterface类实现MyClassOrInterface接口。
在构造类图、顺序图和状态图期间,检查R005~R008,遇到错误直接throw。类图构造完后,检查R001~R004,遇到错误也throw出来。在MyUmlGeneralInteraction类的构造方法中,catch所有的R001~R008,如果catch到了就在ErrorRecord类中记录下来。在之后官方包调用checkForUml001~checkForUml008时,直接到ErrorRecord里去找是否之前抛出了此类错误,如果是就直接抛出。
二、本学期架构设计及OO方法理解的演进
架构设计总结:
作业 |
架构设计特点 |
第1次作业 |
写了多个类,分别是项类、多项式类、正则解析类和主类,分开了职责。 |
第2次作业 |
一个类专门负责化简,三角函数化简规则写成接口,方便更换。 |
第3次作业 |
各个类别的项实现Term接口,实现自由的嵌套关系。 |
第5次作业 |
第一次用生产者消费者模式;一开始不确定使用什么调度算法,于是让调度算法类实现调度算法接口,使用接口的方式,未来方便更换调度算法。 |
第6次作业 |
一个生产者多个消费者,生产者来分配任务。 |
第7次作业 |
Master-Worker模式 |
第9次作业 |
完全按照JML来写 |
第10次作业 |
完全按照JML来写 |
第11次作业 |
写了最小堆类、并查集类和深搜类,但与作业中的其他类耦合比较高(如:直接传入MyPerson对象作为参数)。 |
第13次作业 |
适配器模式;通过Association/Generation/Realization三个接口来统一MyClass和MyInterface的部分行为;类图的元素没有分层地管理(MyUmlInteraction中管理了所有的MyClassMy,MyOperation,MyAssociation等) |
第14次作业 |
顺序图和状态图中的元素,分层地管理(如state由statemachine管理,statemachine由statemanager管理) |
第15次作业 |
通过Node接口,将类图中的类和接口抽象为图的节点;加了一个MyClassOrInterface接口,其继承Node/Association/Generation/Realization四个接口,MyClass和MyInterface改为实现这一个接口;在MyUmlGeneralInteraction的构造方法中使用一个try多个catch,捕获在解析uml的时候发生的错误,记录下来,在checkForUml00x()方法中再将其抛出。 |
在架构设计方面,我慢慢习惯使用接口来提升程序的可扩展性,这样当出现新需求的时候就可以比较方便地添加功能。逐渐学会把类的职能分开,每个类专注做自己的事,减少类之间的耦合,这样在修改的时候,就会减少“牵一发而动全身”的情况。在编写多线程的程序的时候,学会了使用设计模式来让自己的程序更可靠。
三、对测试理解与实践的演进
我大一写C的时候,自己测,一般是先几组正常的数据,再测几组极端的数据,都没问题的话剩下的直接交上去给OJ测了。
在面向对象课程里,对自己测试的要求提高了好多,自己不好好测试,指望平台的中测数据来测试的话,强测一定炸。
首先是黑盒测试。对功能的测试,要全面,覆盖到每一个功能的每种情况。然后是极端数据的测试,包括符合输入规则的极端数据,和用户可能随便瞎输入的极端数据。这时候通常需要大量的测试数据,一方面分门别类总结出尽可能覆盖所有情况测试数据,一方面通过自动化测试的方式,暴力生成大量测试数据。
然后是单元测试。针对每个类的每个方法进行单独的测试。因为如果每个类每个方法都是正确的,再加上架构的设计没有问题,通常整个程序就是正确的。单元测试也可以更有针对性地构造数据、找到问题。
四、课程收获总结
首先是对Java语言本身的机制有了更进一步的了解。比如各种容器的原理与使用、多线程程序如何编写,继承、封装、多态,接口等等。并且通过大量的作业,感觉自己写的代码越来越“OO”了,慢慢在写的时候会考虑到类之间的耦合度、未来的扩展性等问题。
初次接触了设计模式,由前人大佬的编程经验总结出来的模式。在实验和作业中应用了工厂模式、生产者-消费者模式、master-worker模式和适配器模式。
初次接触了多线程的程序,理解了对共享资源要做互斥的保护,学习了同步锁、读写锁,以及通过设计模式来完成多线程的任务。
初次接触了JML,从一个更宏观的角度来看一个项目。见识了用形式化语言来描述代码的功能,并通过纯数学推导的方式来验证程序正确性的思想。但是学完之后,感觉JML相关工具链还不是很成熟,纯数学的推导也不知道具体要怎么推导法。但是这种通过忽略细节,从一个更高的视角来看整个项目,感觉很有意义。以后工作中用的不一定是JML,也不一定是Java,但这种思想都是可以相通的。
初次接触了UML,学习了类图、顺序图和状态图的结构组成,从更高的视角来看一个项目。
五、给课程提三个具体建议
1.checkstyle
checkstyle的初衷是养成写代码的好习惯,写出来的代码不仅功能正确,而且美观、优质。但是里面有一些指标,实际上是可以通过特殊的方式来绕过的(我自己就用过)。举例来说:
一行不得超过80个字符。这个规则的本来是想让我们不要一堆操作挤在一行,可读性差。好的解决办法是,一行长的代码,有条理地拆分成几行小代码,逻辑清晰可读性还强。但绕过的解决办法就是,在这行代码出现括号的地方直接回车,强行换行。
一个文件不能超过500行。这条规则也是希望我们能贯彻落实“单一职责原则”,不要什么都往一个类里塞。但绕过的办法就是,大括号的后半个(“}”这个符号)都叠在一行里,能瞬间减少好多行。
我自己经常欺骗checkstyle....但感觉这样对自己并不好。要是能做到的话,希望对checkstyle的检查能严格一些,能查出这些绕过的方式。
2.实验反馈
希望每次实验课完成之后能得到反馈,知道自己的实验哪里做的有问题。
3.交作业时给提示
希望能在每一次提交代码的时候,提示“请确保代码中没有出现您的姓名;请确保没有提交官方包;请确保您在代码中没有保留jml注释”。
六、线上学习OO课程体会
线上学习有个好处是,看视频的时候,没看懂的地方可以回看,简单的地方可以快进,来去自如。
OO的作业和实验本来就全都可以在家完成,在疫情期间相比于其他专业同学的课程可能会有更好的体验。在家里十分懒惰,所以多亏了每周的deadline,让自己每周能有动力学习。