BUAA OO 第四次作业总结
第四单元架构设计
第十三次作业
按照 UML 图建立类和关系即可。
需要注意的是输入的顺序是随机的,但是 UML 的 parent_id
隐含了一个继承的关系,所以我才用的是每次只读取一种 UmlElement
的方法,多次读取:
for (UmlElement element: elements) {
if (element instanceof /* ElementType1 */) {
// ...
}
}
for (UmlElement element: elements) {
if (element instanceof /* ElementType2 */) {
// ...
}
}
// ...
读取的顺序如下:
- UmlClass
- UmlInterface
- UmlAssociationEnd
- UmlAttribute
- UmlGeneralization
- UmlInterfaceRealization
- UmlOperation
- UmlAssociation
- UmlParameter
同时,这个单元我用了大量的 Stream 简化代码。Stream 真好用()
第十四次作业
增加了状态图和顺序图,和上一次作业差别不大。解析的顺序为:
- UmlClass
- UmlInterface
- UmlAssociationEnd
- UmlAttribute
- UmlGeneralization
- UmlInterfaceRealization
- UmlOperation
- UmlAssociation
- UmlParameter
- UmlStateMachine
- UmlRegion
- UmlState
- UmlFinalState
- UmlPseudostate
- UmlTransition
- UmlEvent
- UmlInteraction
- UmlLifeline
- UmlMessage
第十五次作业
这次作业主要加入了错误 UML 的判断。因此架构上基本不变,但是为了解耦,我单独分出了一个 Parser
类用来解析 UML 元素。
实现上的难点主要在于判断循环引用等,这个可以用 DFS 实现。简单计算不难发现暴力 DFS 并不会超时。
另外就是要注意对于各种“判断是否重名”/“判断是否存在”的 Rule,要搞清楚他们分别在说什么。这里没有规格,而且语义表述有点模糊,还是比较麻烦的。
架构设计总结
我觉得每个单元的架构设计思路都是不一样的:
- 第一单元强调用“对象”来模拟一个已经存在的东西(一个“数学对象”),而不是另一种抽象的模型
- 在这个单元设计架构时,我以数学定义为基础,根据 BNF 语法来设计架构层次,只需要定义“表达式”/“项”等类即可
- 这样设计的好处是贴近现实,一定程度上降低了复杂度
- 第二单元的主题是“多线程”
- 很明显,这个单元和第一单元不一样,加入了“生产者消费者”模型的概念,强调以一个抽象模型为基础进行设计(我认为这个单元最接近 Design Patterns)
- 因此我在设计架构时,以“生产者消费者”模型为基础,加入调度器等设施,设计“Producer”/“Consumer”/“Controller”等类
- 第三单元强调“规格化”
- 相比起前两个单元,这个单元的设计“几乎”已经通过规格给出了,因此我设计的基础也是给出的规格
- 同时,也要考虑到性能等因素,加入一些Cache,此时会引入一些额外的对象
- 第四单元以 UML 为基础,在现有的模型上进行改进
- 其实这个单元有点像第一单元和第三单元的结合,因为 UML 的结构已经定义好了,我们要做的是在此基础上添加自己想要的内容
- 但是这个单元在设计架构时比第三单元更加灵活,因为没有了规格的定义,十分符合“适配者模式”
对 OO 的理解演进:
- 一开始我认为 OO 的发明只是为了代码复用,例如“继承”技术等
- 现在我认为 OO 最大的作用在于解耦和隐藏复杂度。架构设计的关键在于“封装”,而“代码复用”则是一个副产物。
- 代码复杂度和代码量之间并不是一个“线性关系”,而是一个“高次多项式”甚至是“指数”的关系。通过设计上的“解耦”,我们能够将一个工程分解成几个小架构,然后逐个击破(有点像因子分解)
- 只要保证每个组件的正确性,以及组件间“关系”的正确性,我们就能保证整个系统的正确性
- 无论是“面向对象”,还是“面向规格”,或者是“设计模式”,他们被发明的目标都是为了应对工程的复杂度。
工科的历史就是人类与工程复杂度塔塔开的历史
而博客作业则是同学们与 OO 作业塔塔开的见证
测试总结
- 在第一单元中我使用了 Python + Sympy 作为数据生成和测试手段
- 一开始效率比较低下,后来通过减小“数字”的规模来加速
- 在第二单元中我以手动测试为主(主要是各种边界情况)
- 第三单元以肉眼 Debug 为主,因为规格是固定的,所以阅读代码找漏洞比较方便
总结来说,最好的测试方法是“随机” + “构造”。
课程收获
- 在第一单元学会了根据对象的属性分割出“类”和“接口”(同时学到了递归下降,感觉有点像写解释器了)
- 在第二单元进行了多线程的简单实践,学到了锁的产生原因和避免
- 在第三单元学到了规格化编程的思想
- 在第四单元学习了 UML 类图相关的知识
除此之外:
- 学会了熟练使用各种“容器”:虽然以前参加竞赛写过 C++,但是一直不习惯使用容器,而是习惯用自己手写的。经过这门课的学习,我也变成了“调库侠”(褒义)了
- 学会了“封装”,以及各种 OO 的规范和 checkstyle
- 学会了熟练使用函数式 API(Stream 永远的神)
- 知道了一些工程上的概念,例如代码的“圈复杂度”等
- 熬夜技能更加熟练了!
改进建议
- 增加可选的预习环节
- 个人感觉似乎每个单元中最难熬的都是第一次作业(第一单元除外)。无论是第二单元“对多线程的使用”,还是第三单元明白“什么是规格”,以及第四单元理解“UML 的结果”,在经过第一次作业后都感觉轻松不少。相反的是,与之相邻的博客周却非常轻松。
- 因此我认为可以在博客周提前发布一些可选的预习任务或者资料,让同学们提前了解下一单元的内容
- 可以的话希望能在寒假预习中提一下“递归下降算法”,让同学们提前了解
- JML 单元的改进
- 据收集资料,我发现网上很少有有关 JML 的资料,这个工具使用的似乎也比较少(不过看了一些资料,好像也没有更好的选择就是了)。
- 感觉可以加入关于防御式编程的普及,例如推广
assert
的使用 - 此外,我建议可以加入各种测试方法实践(单元测试/回归测试/etc)
- 如果要加入新内容的话,可以考虑削减部分原来的任务量
- 设计模式
- 这门课有很多实践内容,但是似乎对于“设计模式”本身的介绍比较少,都是靠同学研讨课普及,或许可以考虑加一些阅读材料?(为什么不推荐在考试里面加呢,当然是为了减轻同学的压力(
- 给出一些 Best Practice
- 希望课程组能选出同学中比较好的一些代码或者架构,让同学们能互相学习。
- 不然实验做下来,虽然自己做的有问题但是却不自知还是比较难受的。
- 希望能减轻“互测”的强度
- “互测”感觉很耗费精力,希望能适当减轻一下强度
- (小声)建议加入函数式编程的科普