BUAA-OO2022-UNIT4总结
1. 四单元架构设计
本单元建立一个UML解析器,最主要的工作在于接收到各种UML元素,然后将其组织在恰当的数据结构中,之后再基于此数据结构进行各种查找。
如图是我最后一次作业的代码目录,对不同的UML元素进行不同的封装,从而实现有效的管理。
类图
类图可以分为三个层次,由于不同层次间存在不同的关联关系,因此利用三个for循环分层读取。
- 第一层:class,interface, associationEnd(此处与层次不对应,因为association会指向两个associationEnd,但associationEnd中不含有其所在的association信息)
- 第二层:UML_ATTRIBUTE、UML_OPERATION、UML_GENERALIZATION,UML_INTERFACE_REALIZATION
- 第三层:UML_PARAMETER
对class、interface、operation、associationEnd进行封装。
时序图
注:此图有缺漏,实际上UMLCollaboration还有一个UmlAttribute属性!
时序图分四个循环进行读取
- 第一层:UMLCollaboration
- 第二层:UMLInteraction, UMLAttribute
- 第三层:UMLLifeline(在interaction中记录), UMLEndpoint
- 第四层:UMLMessage,建立创建关系,记录lost和found
对collaboration、lifeline、transition进行封装
状态图
状态图也用四个for循环:
- 第一层:UMLStateMachine和Region
- 第二层:UmlPseudostate,UmlState,UmlFinalState
- 第三层:UMLTransition,保存在hashmap中,并记录好对应的state;
- 第四层:UMLEvent
总体逻辑
以下代码是MyUserApi构造函数的主要逻辑,分层解析各种元素
for (UmlElement e : elements) {
//类图第一轮——最上层:class, interface, association
processClassModel1(e);
//状态图第一轮——UMLStateMachine和Region
processStateChart1(e);
//时序图第一轮——UMLCollaboration
processCollaboration1(e);
}
for (UmlElement e : elements) {
//类图第二轮——中间层:UML_ATTRIBUTE、UML_OPERATION、UML_ASSOCIATION(暂不管)
// UML_GENERALIZATION,UML_INTERFACE_REALIZATION
processClassModel2(e);
//状态图第二轮——UmlPseudostate,UmlState,UmlFinalState
processStateChart2(e);
//时序图第二轮——UMLInteraction, UMLAttribute
processCollaboration2(e);
//Attribute操作合并
if (e instanceof UmlAttribute) {
attributes.put(e.getId(), (UmlAttribute) e);
tmp = classIdMap.get(e.getParentId()); //先看是不是类
if (tmp != null) {
tmp.addAttribute((UmlAttribute) e);
} else {
tmp = interfaces.get(e.getParentId()); //再看是不是类
if (tmp != null) {
tmp.addAttribute((UmlAttribute) e);
} else { //一定是collaboration
collaborations.get(e.getParentId()).addAttribute((UmlAttribute) e);
}
}
}
}
for (UmlElement e : elements) {
//类图第三轮——叶节点:UML_PARAMETER
processClassModel3(e);
//状态图第三轮——UMLTransition,保存在hashmap中,并记录好对应的state;
// 同时在每个状态中记录可达的边
processStateChart3(e);
//时序图第三轮——UMLLifeline(在interaction中记录), UMLEndpoint
processCollaboration3(e);
}
for (UmlElement e : elements) {
//状态图第四轮——UMLEvent
processStateChart4(e);
//时序图第四轮——UMLMessage,建立创建关系,记录lost和found
processCollaboration4(e);
}
有效性检查
在最后一次作业中加入了有效性检查要求。这部分状态图和时序图的检查都可以在原来数据结构上进行简要改进而实现,但类图部分改动较大。
类图部分主要是要检查循环继承、重复继承。我的思路是把继承关系当做一个有向边,类或接口当做结点,因此得到如下的等价:
- 检查循环继承:查找图中是否有环
- 检查重复继承(难点在于接口):查找图中某一结点到其余任意结点是否存在两条路径(有点维护最小生成树的感觉)。
基于这样的图结构,我为每个类/接口新加了一个block属性,分别对应GeneralBlockOfClass和GeneralBlockOfInterface,其中蕴含并查集的思想,在同一个图中的结点都指向同一个这样的block实例。
最终查询时基于图算法处理即可。
2. 四个单元思维和测试的演进
Unit 1
第一单元给我带来的感受是最痛苦的,留下的印象也是最深的,那时我码力很弱,也不会测试,完成一个需要大工程量的面向对象编程题目需要很多时间,特别是最初的时候不知道怎样的架构才是最好的,也经历了重构,更是给人很大压力。
不过好在我有提前看一些学长学姐的博客再下手,采用的是递归下降的方法,也在完成这一单元作业的过程中收获了一些继承和接口应该怎么用的实际经验,对面向对象思维有了更深的理解。
这一单元设计了一个简单的评测机,各种数据随机造,用大量的数据进行测试,但感觉只能检查出比较明显的问题,便于过中测,但在互测时用处不大。
Unit 2
第二单元之前,我提前预习了多线程相关的知识,同时认真阅读了相关的设计模式,参考了课程组给出的实验课的代码后,在架构方面已经比第一单元清晰了很多,最终选择了生产者消费者模式作为主体架构。
本单元作业主要的难点是线程安全性的维护和调度算法的选择。从这单元开始,我开始有意识地搭建自己的评测机,也借此hack了不少同学。
Unit 3
第三单元是最快乐的一单元,尽管只要阅读相关的JML规格就可以实现对应的方法,但我在这单元可以说是得到了最多的训练、思考与进步。我开始注意性能问题,也学习巩固了许多图算法,这一单元对我的算法能力和规范化变成设计和实现能力都有很大的帮助。
这一部分我尝试了Junit测试工具,虽然自己仍然需要写很多代码,但是却能够更有针对性地对样例进行设计,其实在设计测试的过程中也促使我再一次去明晰每个部分的功能和可能出问题的地方,其实我在这部分发现了不少自己之前解时忽略的问题。
Unit 4
本单元的架构很难说没有借鉴之前三单元所学习的东西。我将算法与数据结构分开,利用并查集的思想完成部分查询,这都是前几次作业给我留下的成长。尽管对其他同学来说,这可能是微不足道的一件事,尽管我错误百出,但我真的从OO课程中学到了很多知识。架构与算法设计在上文已经写的很详细了,在此不再赘述。
这一部分仍然利用junit,相较于第一次大量用随机数据无脑测,这一单元的测试样例设计加入了更多对边界条件的思考。
3. 总结自己的课程收获
首先,由于 OO 课是以 Java 语言作为承载,我在代码书写中通过各种渠道也算是熟悉了 Java 基础语法,初步掌握了这门常年霸占编程语言排行榜首位的语言,为今后的职业发展打下了坚实的基础;
其次,其他一些周边知识的学习也是收获满满:git、markdown、正则表达式、多种多样的设计模式…… 物超所值;
另外,抛开语言本身,这门课给我带来了编程能力的无形提升。这一学期既有数量也有质量的代码训练,让我灵活运用代码语言解决实际问题的能力增长,尤其是后两个单元,加强了对数据结构和算法的考察,初步锻炼了我作为计算机专业学生的基本功;
最后,也是这门课的核心,它带给了我面向对象的新思想。我们知道,在如今的软件开发相关职业中,面向对象是一个不可或缺的理念,它是大型程序设计优良性能的保障。我们首先在编写代码的实践中完成对 OO 从感性认识到理性认识的过渡,再在实践中完成对 OO 认识的真理性的检验和发展,不好意思,最近马原学的有点多。在认识和实践的交互中完成思维的飞跃。比如我现在如果要完成某一项代码任务,就会摒弃面向过程的旧思维,而是不自觉地从面向对象的角度思考,将问题引入规范化,模块化、层次化、简洁化的方向,这将是非科班出生的同学永远都无法比拟的优势。
4. 给课程提三个具体的改进建议
- 希望改进ddl的时间,每周六对我来说实在很紧,因为这学期周中有很多事情,包括os的上机等等,导致我经常都是周五下午晚上,甚至周六才开始写oo,如果能改到周日晚上ddl,那就很好了。
- 希望理论课多一些实际相关的内容,特别是后面几个单元,感觉讲授的内容太虚太宏观了,很多听了对作业也没有帮助,或者说也难以在实际写代码时应用上。
- 减小第一单元的开发难度。第一单元难度有些大,而后续几单元的某几次作业难度很小,完全可以合并在一起,富裕出来的时间留给第一单元,不用强行为了每单元三次作业这种强迫症而分配任务。我认为第一单元合适的任务量是4-5次课下作业,一来寒假做的那些pre难度过低,不足以支持多数同学“体面地”完成作业;二来新学期新课程,给大多数同学一个课程的适应期。
完结撒花~✿✿ヽ(°▽°)ノ✿