北航面向对象Round Four
1.第四单元总结
1.1第十三次作业
1.1.1需求分析
本次作业的输入输出接口课程组已经提供了,这无疑给我们减轻了很大的负担,减少了很多精力去理解处理输入输出部分。我们只需要考虑的就是一堆UmlElement
之间的关系,再根据他们之间的关系设计数据结构。
1.1.2架构设计
由于第十三次作业我们只需要解析UML类图
,所以我这里采用了类似于我们平常代码的三级模式。即:类和接口为最高一级,方法和属性为第二级,类包括了方法和属性,第三级为方法的相关属性,例如有无返回值等,所以需要对UmlElement
的数组扫描三次。并且我在外部使用邻接表存储类和接口之间的关系。查询方式采用的是懒查询 + cache
的方法,即每次查询先找cache
中是否存在查询的数据,miss后再进行查询,并将查询结果写入cache
。程序的UML
图如下:
这里我设计了三个类,分别为MyClass
、MyImplement
、MyOperation
。它们的作用和它们的名字一样,都是用来存储相应UmlElement
的信息。这样的架构我相信大家都能想到,也更容易被代码阅读者理解。
1.2第十四次作业
1.2.1需求分析
本次作业的输入输出接口课程组同样也已给出,不过加入了顺序图和状态图,并且对类图提出了新的要求:要求检查给出的UML
类图是否符合某些规范,我们这就必须算出来每个类所继承的接口和类的状况。此外,本次作业还增加了顺序图和状态图,他们都是有明确结构的。并且相关的查询语句也依赖于这个结构,所以可以采用类似于第十三次作业的方法。
1.2.2架构设计
虽然第十三次作业已经有了一些懒查询的方法,但是由于这次要求提前明确每个类和接口的继承状况,我就提前把类和接口继承的属性等记录下来,放弃了懒查询的方法,改为直接查询,新增了MyGraph
类跑拓扑排序明确类和接口的继承情况。在处理顺序图和状态图使用了两级模式,即每个“画布”为一级,每个具体的UML
图为下属一级。程序的UML
类图如下:
这里我新增了MyOrder
类记录顺序图的结构,新增了MyStateMachine
类和MyState
类记录状态图的结构。并使用懒查询的方式查询顺序图和状态图。
2.从课程中学到的架构设计
初识面向对象
第一单元是简单多项式的求导。同时也是我第一次写面向对象程序,对于如何分类也是懵懵懂懂。这一单元的作用是教给我们如何写一个面向对象程序,以及如何应用Java
的继承和接口特性和正则表达式。经过三次作业的训练后,我逐渐掌握了将物抽象为对象的技巧,也掌握了一些Java
语言的特性。拿第一单元的最后一次作业为例,我设计了五种因子:NumFactor
、VarFactor
、SinFactor
、CosFactor
、ExprFactor
。它们分别处理和保存常数、变量x
、正弦因子、余弦因子、表达式因子。另外设计了一个处理项的类Term
和一个处理表达式的类Expression
。输入处理也单独划分为一个类ParseInput
。因为每个Factor有共通之处,我设计了一个Factor
父类,五种因子都继承于此,获得数据处理的方法和根据字符串生成新的因子的方法。好的架构设计的优点在这个时候也体现出来了,最后一次作业是我第一单元写的最快的一次,而且一次就通过了中测和强测。
线程设计
第二单元是多线程电梯,之前就对电梯有所耳闻。多线程最重要的就是对临界区的访问控制,在提高程序效率的情况下避免死锁。本单元的三次作业我都采用了“生产者——消费者”模式。输入接口为生产者,电梯为消费者。临界区存储了等待进入电梯的人。三次作业都是对“生产者——消费者”模式的扩展,最后一次作业有三个电梯,也就有三个消费者。电梯的处理调度算法也是采用的和生活中相同的调度算法。扫描+先来先服务,并没有过度研究性能的优化。由于采用了较为直观的架构设计和单例模式,第二单元苟过。
JML语言
我感觉第三单元的目的是让我们都体验一次“码农”。我们基本不需要对架构做过多的设计,因为本单元的要求细化到了每个函数的功能,这个单元简直就如同架构师给码农提出好代码细节要求后,码农去实现整个工程的过程。JML
语言确实提高了开发团队的工作效率,每个人不必考虑全局,只要考虑自己应该处理的细节即可。但是如果只依靠JML
语言,对架构师的能力要求就比较高,可以说大部分压力集中于一个岗位。言归正传,本单元作业对CPU的时间要求较为严苛,可以说cache
是本单元一个及其重要的东西,也就是用空间来换时间。本单元的架构设计主要围绕在设计一些函数的算法方面,这样暴露了JML
的一个问题,就是规定了每个函数的任务后,多个代码实现人员容易重复造轮子,这样的问题同样需要协商解决。所以我认为,在实际中,只使用JML
语言就可以完美搞定整个工程不太现实,还是需要工作人员的线下商讨。此外,本单元我尝试了几次直接继承“屎山”的行为,发现这个过程是真的难受,如果对下次作业有较好的预测的话,那代码实现的过程是非常舒服的。如果预测错了,那就是灾难了。代码迭代的过程确实不容易,且行且珍惜。
面向对象的架构设计
总的来说,第四单元的代码作业感觉和第三单元是一个风格——要求CPU时间,规定好了每个函数的输入输出,只是工程量较第三次作业可能大了一点。感觉第四单元学了UML
的设计方法外,就没再学到更多的东西。第四单元我采用了比较贴近现实的架构设计,即按照实际中的UML
图结构划分层次存储相应的数据,在查询相关数据时采用cache
,加速查询速度。此外,本单元还教会了我们如何使用StarUML
(小声吐槽一下,这个软件有时候会比较卡,像P3的Logisim
),用这个做需求分析和设计还是很好的,很直观。
3.从课程中学到的单元测试方法
第一单元
第一单元主要是使用python做脚本测试,因为python也有正则表达式库,也有自动求导功能,我们可以开发一个和评测机差不多的judge平台,利用管道对java
进行输入输出控制。正确性检查方法和评测机的检查方法相同,也是带入一堆数算多项式的结果,最后进行结果对比。但是这个评测机的一个问题就是,不能随机产生错误的数据,即之只能验证合法输入的结果是正确的,而不能验证非法输入结果的正确性。像这种非法输入就只能人为构造然后进行测试了。
第二单元
第二单元是多线程电梯。我的主要测试方法是梳理设计架构和设计细节。因为多线程的bug
多出现于临界区的访问冲突,从而导致数据不一致或者是死锁的情况。这时候梳理各个线程临界区的访问顺序就极为重要,明确每个线程何时会申请锁,何时会修改临界区,何时会释放锁后,一般就很难再出现线程的问题。其它可以复现的bug
都不是bug
。
第三单元
第三单元我们主要使用了jjc
的测试方法,即利用大家生成jar
包的代码,输入相同的数据,对比大家的输出,如果大家输出一致,那么问题就不大;如果有人不一致,那么肯定有bug
出现了,评测机就会反馈出现bug
的位置和bug
的现象,然后就可以开始愉快地debug
了。这个jjc
的原理是:如果一个人的代码出现bug
的概率是\(10\%\),那么5个人的代码出现相同bug
的概率就远小于\((10\%)^5\)。这样会大大提高我们的正确率。
第四单元
第四个单元我们继续延续了第三单元的测试方法,简单来说就是对拍,不过大家需要分工画出一些UML
图。大白同学的评测机会自动生成一些测试指令,然后大家提交jar
包进行对拍,这样的测试效果是比较好的。在此感谢sdy和大白提供的jjc
。
4.课程总结
这个课程的首要收获当然是学会了java
这门语言,学会了写多线程程序。java
语言的学习确实很有用,本学期的《图像处理与模式识别》作业的代码同样也是用java
完成的,并且在《网络攻防》这门课中用到了多线程的技术。可以说面向对象这门课很基础,很有用。
当然,这门课最大的收获是学习了一些有关面向对象设计的思想,以及一些设计模式。包括但不限于:如何抽象一个类,如何抽象出继承关系,单例模式,工厂模式,JML
建模语言,UML
建模语言等。这些设计思想在进行代码的架构设计中非常有用,一个好的设计不仅可以让你快速写完代码,还能让代码有良好的扩展性,应对新的功能。
这门课的一个顺带收获是提高了代码能力,毕竟十多次作业,还是写了不少代码的。学会了一些debug
的方法和线下测试的方法,这些也是宝贵的经验。上完这门课后,理解了为什么java
这门语言为什么这么火,不仅是因为它的代码十分灵活,运行效率高,还因为他是面向对象语言的典范。彻底粉java
了。
还一个对我影响比较深的收获,就是我们的checkstyle
。这个东西就像是一个练字帖,让我们写的代码更规范了,同时也在随时提醒我们要养成良好的代码风格。这个功能确实好评,希望继续延续下去。
5.课程建议
- 四次课程的顺序安排感觉不太好,可以调整为1,3,4,2的顺序,最后写多线程程序。今年的这个顺序感觉多线程之后难度突然下降,就没怎么有写
Java
的欲望了。 JML
和UML
感觉代码部分有点重复,像是在反复练习架构设计。个人感觉JML
可以和UML
放在一起讲,这样可以空出来一个单元学习新的内容。