1 正向建模与开发
正向建模与开发是指从高层次的抽象模型逐步转化为具体的实现。在本单元中,我大致经历了以下的步骤,实现代码的编写:
-
需求分析:仔细阅读指导书,大致记录图书馆和图书馆下的预约处、借还处、漂流处等不同的需求,并从用户角度分析借书、还书、预约等流程。
-
系统设计:根据需求,设计大致的架构与模块,运用UML创建图书馆系统的静态模型,主要是使用类图,分析不同类之间的关系以及一些可能会用到的函数。根据用户借书、还书、预约等流程,画出对应的状态图与时序图。但是,在具体的实践中,我有必要反思:由于刚开始接触UML模型,并且不熟悉图的画法,最开始的类图、状态图、时序图是在草稿纸上生成的,具体的图的实现都是在代码编写后进行的。
-
代码编写:根据以上的设计进行代码的编写,实现图书馆系统的各个功能模块。
-
测试与验证:对于一些细节,自行构造一些数据,还有就是通过同学的测评机来debug。
2 本单元作业的架构设计
2.1 第十三次作业
Main类
图书馆采用单例模式,在Main
中创建,所以Main
类和Library
类之间也是关联关系。
Library类
图书馆类统一管理借还处、预约处的图书,用户在图书馆类中完成借书、还书、预约、取书等操作。作为主管机构,图书馆类与其下设的预约处(OrderOffice
类)和借还处(BorrowAndRreturnOffice
类)都是关联关系。因为图书馆中还记录了用户名单,所以图书馆类与Student
类也有关联关系。
OrderOffice类
预约处类,为了记录书号、预约者、日期等信息,重新创建了一个OrderedBook
类,在OrderOffice
中有一个OrderedBook
的ArrayList
,所以,OrderOffice
与OrderedBook
之间也有关联关系。
2.2 第十四次作业
DriftOffice类
本次作业新增漂流角类,归于图书馆类管理,用户的捐赠、借还非正式图书、非正式图书的升级都在图书馆内进行,在Library
中有一个DriftOffice
类的实例化,所以Library
类和DriftOffice
类之间也是关联关系。
2.3第十五次作业
架构与第十四次作业一致,增添了用户信用积分机制,用户的信用积分管理也是在图书馆内随着借阅、还书、预约、取书、整理、漂流等流程进行。
3 四个单元中架构设计思维的演进
3.1 第一单元
第一单元是多项式表达式化简。当时对面向对象的了解只停留在先导课上,初次独立实现一个完整的面向对象的程序时,确实让我犯了难。
第一单元中:
-
PreProcess类:预处理阶段
-
Token类,Lexer类与Parser类:递归下降与表达式解析
-
Factor类,Term类和Expr类:数据结构
当时我自己本身对于面向对象的设计还不太清晰,以上的类都是根据公众号的递归下降讲解以及实验代码构造的,对于与计算相关的Mono类和Poly类,是参考学长学姐的实现方式而构造出来的,可见初期的我在架构设计方面还比较薄弱。
通过第一单元的作业,我初步了解了面向对象的形式,也在完成作业的过程中体会到了面向对象中实现,继承和多态的特性,对于这些特性的运用,初步感受到了面向对象的便利。同时,本单元最重要的一个特征就是实现层次化设计,不论是表达式递归下降的层层解析,还是计算中层层嵌套,都能体现层次化的思想。
3.2 第二单元
第二单元模拟电梯运行。第一次接触多线程编程,面对第五次作业有点无从下手,实验中以及课堂上老师讲解的的“生产者-消费者”架构为我提供了思路。在实验架构的基础上,我增添了调度策略算法、电梯运行策略分析,实现一定的层次化设计。
同时,为了实现调度器的统一化,我还采用了单例模式,在全局中只实例化一个调度器对象,使调度器能够更好地统筹全局,同时,在调度器中新建双轿厢电梯,使用单例模式有利于DCReset的实现。
但是,其实在最最最开始的时候,我没有形成完整的流程和功能模块的分析,导致最初的代码写得磕磕绊绊。在面对多线程编程时,要首先根据需要实现的功能,分成多个不同的功能模块,利用前驱图,调度关系,梳理各个线程之间的同步与互斥关系,避免死锁、无人唤醒等异常情况。并规定好不同模块之间的接口,利用共享对象传递信息,然后再自上而下依次实现。
3.3 第三单元
第三单元是JML规格化设计,本次作业与图论的知识关系较大,要完成的是对人际图的构建与分析,本单元的架构基本由官方包搭建好了,需要我们正确理解JML描述。
还有需要考虑一些算法、性能层面的问题,本次作业需要查询两个人之间是否连通,所以单独建立并查集类,封装数据容器并统一管理。
本次作业让我开始有了架构优先的认识,对于一个工程,首先需要有明确的需求,实现规格化设计,考虑每一部分的功能以及可扩展性,而忽略使用的数据结构和具体的方法。最后,依据设计填充代码,在这个过程中,我们还需要考虑有利的数据结构,以及性能、算法的优化。
3.4 第四单元
第四单元是学习UML统一建模语言,本次作业强调正向建模与开发,利用UML创建系统的静态和动态模型,包括用类图、状态图、时序图。代码架构的整体设计也是在这一步完成,在简单绘制类图时,先根据不同模块(比如图书馆、用户、借还处等)单独建类,再合理组织每一个模块之间的关联、继承等关系,实现图书馆总管理,将各个功能分配到不同的类中完成,架构也比较直观。
同时,根据流程,需要提前绘制状态图、时序图,才不至于代码编写时没有一个整体的框架,但是由于我刚开始接触UML,所以这个步骤是在草稿纸上实现的。
4 四个单元中测试思维的演进
在第一、二单元中,过于依赖测评机,自以为跑了很多次测评机没有出现问题就是完全正确了,没有对代码进行更加精细的检查,导致第三次作业挂了。但是,反过来思考,测评机采用的是随机测试,而在测试中覆盖率才是最重要的影响因素,对于极端数据几乎难以进行有效覆盖,所以不能太依赖测评机。
第三单元中,Junit测试为我们覆盖测试提供思路,当JUnit测试检验代码实现与规格的一致性,即可验证代码功能的正确性,同时有利于检查边界条件、发现与修复问题。当需要对代码进行重构或修改时,JUnit测试可以作为安全网,确保修改后的代码仍然符合规格要求。通过运行测试用例,可以验证修改是否影响了代码的功能和行为,从而保证系统的稳定性和可靠性。
但是由于在作业中,为每一个方法构造JUnit测试是不现实的,所以,在所有的作业中,以测评机为主,用python进行测试数据生成和对拍。对于边界条件,需要自行构造一些样例。
5 课程收获
虽然是一段痛苦的旅程,但是通过面向对象的这门课程,我不仅学会了一门编程语言,更多的是体会到面向对象的编程思想,同时还接触与了解了JML规格和UML统一建模语言,收获颇丰。
在课程学习的过程中,我从过去的面向过程的编程思想逐步过渡到面向对象的编程思想,在我看来,尽管这二者有显著的不同,但其实他们之间并非割裂,在面向对象模块内部方法主要还是依靠面向过程的实现。
另一个方面,在架构的设计与构造中,课程让我明白合理的模块和层次设计不仅可以满足良好的可扩展性,另一方面其实也可以简化代码的工程量。在第一单元和第二单元的作业中,架构设计的重要性不言而喻,一个好的架构具有可扩展性,在每次作业的迭代中会相应地减少一点工作量。
虽然学习的过程艰难,并由于自己粗心的毛病,在两次作业中获得很不理想的成绩,但是还是很感谢OO这门课能让我熟悉架构设计,熟悉规格方法以及UML统一建模,让我看到自己在一点点进步,心理素质也一点点提高。
最后,感谢OO课程组的老师、助教学长学姐们,感谢我的好朋友们,感谢他们的每一次帮助和支持,我倍感温暖与感激。
“追风赶月莫停留”,来日之路光明灿烂,继续加油吧!