本单元作业的架构设计
类图
分析
为了满足 checkstyle 对于类行数的要求,我把对于类图、顺序图、状态转移图以及检查的功能全都单独放到一个类中,分别对应图中 ClassApi, SequenceApi, FsmApi, CheckApi. UserApiImpl 只需要进行初始化,然后直接调用上四类提供的查询方法。其中 Utils 是将 UserApiImpl 初始化单独抽出的组成的工具类,InitialBehavior 是 UserApiImpl 的初始化接口。 其他 Integrate 开头的类是对 UmlElement 的包装,增加冗余的信息加速查询。IntegrateElement 接口是为了便于书写的而实现的,目的在于可以直接对 Integrate 的类调用 getName 方法等,而不用每次都先 getElement 再 getName。别问为什么设计地这么复杂,问就是被 checkstyle 恶心了。
四个单元中架构设计思维及OO方法理解的演进
第一单元
第一单元的架构就是一个小型编译器了,只不过目标语言是去括号后的表达式,不需要生成中间代码,也没针对三角函数进行优化。模块化比较明显,整体分为了四部分,词法分析器、语法分析器、语法树元素、最终表达形式。语法树元素都实现了同一接口。整体而言我还是认为这和面向对象关系不大,面向对象的核心在于多态,而只有语法树用到这种特性,其他部分多用递归思路。而且我必须要给面向过程正名,类似“一main到底”这种糟糕的代码风格根本不能叫做面向过程,应该叫做面向 OJ(当然并不是说所有 OJ 代码都是这样),没有必要借此而去说面向过程不好。本质上面向过程是贴近机器的思维,面向对象是贴近人类社会的思维,如是而已。
第二单元
第二单元采用了流水线式的架构,各流水段间采用生产者消费者模型进行传递信息。特别需要注意反馈回路防止死锁,这个本地测试还不好测,太痛苦了。
第三单元
第三单元基本没什么架构,就根据 JML 实现对应的方法即可。针对高复杂度的方法,往往独立设置相应的适合的数据结构进行计算并尽可能缓存结果。主要需要解决时间复杂度的问题,其他方面都比较简答。
第四单元
第四单元也没什么需要架构的,完成特定的方法即可。只不过为了便于查询需要针对 UML 元素进行封装,并填补相关数据,因而需要在初始化的时候多做一些工作。剩余的内容就又回到算法与数据结构了。
OO 思想
前文也已提及,OO 的灵魂在于多态,而多态的基础在于对于对象的抽象,对于对象的抽象源于人类对于世界的认知。人对世界的直观认知必然不是一堆按一定规律排列的分子原子,而是一个个的物品(对象),物体就具备自身的属性(外形、颜色等)和方法(即用途)。OO 就在于将问题分解后分配、委派给抽象出的对象,抽象出的层次不同也就导致了多态(高层次的抽象是低层次抽象的父类)。其和面向过程的区别就在于前者最低层次在于对象,而后者最底层次在于数据和指令,最基本的对象的内部实现依然是面向过程的,就好像现实世界里再简单的物体也是由原子组成的。
四个单元中测试理解与实践的演进
第一单元采用了随机大批量生成的测评机,第二单元和第一单元类似,但是没办法检查死锁导致强测寄了。第三四单元就没有进行测试。
但是总的来说,大型项目肯定需要进行白盒测试,所以契约式编程就很重要,单线程程序出bug大多都是实际输入约束和心中所想的输入约束不符。
课程收获
- 熟练了java语言
- 第一次上手写了多线程程序
- 认识了 JML 和 UML
改进建议
- 上课、答疑等不要拐弯抹角,不要讲类似大道理之类的话,大家都是成年人。
- 个人不喜欢太多花里胡哨的教学形式,实验、理论、作业、研讨形式太多,比如实验课完全没有存在的必要。
- 个人感觉前两个单元讲的太少,做的太多;后两个单元讲的太虚,作业也太虚。所以作业和课程应该联系紧密一些,前两个单元的作业不要故意整的复杂怪异,后两个单元最起码先讲点基础的东西,而不是上来就开始“指点江山”。