BUAA_OO_Unit4 UML解析暨课程总结
BUAA_OO_Unit4 UML解析暨课程总结
一、综述
面向对象课程的第四单元的主题是学习UML图的结构,分析UML图元素的关系。同时,本单元是本学期面向对象课程的最后一个单元,需要对本学期的学习理解和课程收获进行一个总结。
二、作业分析
1. Homework 13
1.1 整体架构
|- MainClass:主类
|- MyImplementation:作业接口类
|- MyProcessor:Uml图元素解析类
|- classdiagram (package):类图元素包
|- MyAttribute:属性
|- MyClass:类
|- MyOperation:操作
|- MyInterface:接口
1.2 架构设计
本次作业主要实现一个UML解析器,使其支持对UML类图的分析。
在MyProcessor类中按照下列读取顺序读取官方提供的类图元素,构建MyClass、MyInterface、MyAttribute、MyOperation类,然后按照从属关系搭建一个关系树:
- UmlClass|UmlInterface
- UmlAttribute
- UmlGeneralization
- UmlInterfaceRealization
- UmlOperation
- UmlParameter
对于一些涉及查询元素名的指令采取两种容器存储:
private final HashMap<String, ArrayList<MyClass>> classMap; // Hashmap<name, ArrayList<>>
private final HashMap<String, MyClass> classes; // Hashmap<id, Object>
Hashmap
保证id
不会重复,并且将同一个name
的元素用ArrayList
存储。
在判断两个操作是否是重复操作的时候:
private final ArrayList<String> inReTypes;
private final ArrayList<String> inNaTypes;
public boolean equals(MyOperation it) {
Collections.sort(inNaTypes);
Collections.sort(inReTypes);
Collections.sort(it.getInNaTypes());
Collections.sort(it.getInReTypes());
if (name.equals(it.getName()) && inNaTypes.equals(it.getInNaTypes())
&& inReTypes.equals(it.getInReTypes())) {
return true;
}
return false;
}
用两个ArrayList
存储NamedType和ReferenceType两种传入参数,NamedType型参数存储其Name,ReferenceType型参数存储其ReferenceId,然后调用ArrayList
的字符排序和equals
比较方法,可以快速比较参数列表是否相同。
2. Homework 14
2.1 整体架构
|- MainClass:主类
|- MyImplementation:作业接口类
|- MyProcessor:Uml图元素解析类
|- classdiagram (package):类图元素包
|- MyAttribute:属性
|- MyClass:类
|- MyOperation:操作
|- MyInterface:接口
|- orderdiagram (package):顺序图元素包
|- MyInteraction:交互
|- MyLifeline:生命线
|- MyMessage:消息
|- statediagram (package):状态图元素包
|- MyBFS:BFS查询类
|- MyRegion:画布
|- MyState:状态
|- MyStateMachine:状态机
|- MyTransition:转移
2.2 架构设计
本次作业在上次作业的基础上加入了顺序图和状态图的相关查询接口,实际上也是按照类图建树的概念建一个顺序图的树和状态图的树,解析的顺序为:
- UmlClass|UmlInterface
- UmlAttribute
- UmlGeneralization
- UmlInterfaceRealization
- UmlOperation
- UmlParameter
- UmlStateMachine
- UmlRegion
- UmlState|UmlFinalState|UmlPseudostate
- UmlTransition
- UmlEvent
- UmlInteraction
- UmlLifeline
- UmlMessage
其中关于关键状态的查询采用BFS
算法,删除某状态后对所有FinalState看Pseudostate是否都不能到达:
public boolean isReachable(String s, String d) {
for (String str : visited.keySet()) {
visited.put(str, false);
}
Queue<String> queue = new LinkedList<>();
queue.offer(s);
visited.put(s, true);
while (!queue.isEmpty()) {
String u = queue.poll();
for (String v : adj.get(u)) {
if (v.equals(d)) {
return true;
}
if (!visited.get(v)) {
visited.put(v, true);
queue.offer(v);
}
}
}
return false;
}
3. Homework 15
3.1 整体架构
|- MainClass:主类
|- MyImplementation:作业接口类
|- MyProcessor:Uml图元素解析类
|- MyCheck:Uml图元素验证类
|- classdiagram (package):类图元素包
|- MyAttribute:属性
|- MyClass:类
|- MyOperation:操作
|- MyInterface:接口
|- orderdiagram (package):顺序图元素包
|- MyInteraction:交互
|- MyLifeline:生命线
|- MyMessage:消息
|- statediagram (package):状态图元素包
|- MyBFS:BFS查询类
|- MyRegion:画布
|- MyState:状态
|- MyStateMachine:状态机
|- MyTransition:转移
3.2 架构设计
本次作业在上次作业基础上增加了给UML元素和之间的关系做了规范性验证的要求。同时,在上次作业基础上增加了某字段为空的定义(这会影响建图时Hashmap<name,ArrayList<>>
的存储。
为了不改变之前作业的架构和降低查询功能和规范性验证功能的耦合度,我将所有规范性验证都放在MyCheck类里进行,只有通过了所有规范性验证后调用第一条查询指令时才开始建造类图、顺序图、状态图的树:
public MyImplementation(UmlElement... elements) {
this.flag = 0;
this.check = new MyCheck(elements);
this.processor = new MyProcessor(elements);
}
// ClassModel
@Override
public int getClassCount() {
if (flag == 0) {
processor.initial();
flag++;
}
return processor.getClassSum();
}
关于循环继承的查询,采用BFS
算法,将所有类(接口)按照继承的关系连接起来建立有向图,当出现循环继承时,说明有一条从自己到自己的一条路径。
三、架构设计思维及OO方法理解的演进
1. Unit 1
第一单元作业是表达式化简,在这一单元作业中,我是第一次尝试用对象来抽象一个具体的数学模型。同时也是初步理解和掌握层次化设计,依照多项式的结构建立抽象层次,再根据不同的层次进行代码和数据的封装,即构建一个类。一个类可以帮助管理逻辑相关的代码和数据,方便维护和使用,这些代码对外部是不可见的,仅依靠接口进行交互。总的来说就是学会了分析问题、设计层次性的架构,根据架构进行数据封装。
2. Unit 2
第二单元作业是电梯调度,在这一单元中,我初步理解了并发程序中的线程协同与线程安全,学习了基于线程、共享、交互的面向并发和协同抽象的层次设计结构,并且学习了如何维护线程安全的方法以及各种锁的使用。
多线程的执行顺序和数据交互造成了多线程的不安全性,合理利用锁来维护线程安全,同时合理wait-notify,避免轮询占用资源。此外,我还学习了“生产者消费者“模型、”流水线“模型等设计模型。
3. Unit 3
第三单元是学习JML规格,在这一单元中,我学习了JML规格并理解了基于规格的程序设计,即如何让代码更加具有逻辑性和层次性。除JML之外,还学习使用了并查集、堆优化的Prim等多种图论算法来提升效率。
4. Unit 4
第四单元是考察UML图的理解和解析。如何理解UML图各种元素之间的关系并做到归一化管理是本单元作业的核心,UML图本就具有一定的层次,而将这些有层次关系的元素按照自己的逻辑层次关系进行封装处理是本单元作业最重要的一步。
面向对象(Object Oriented)是软件开发方法,一种编程范式。其实不然,面向对象不局限于某种具体的方法,即面向对象不是工具,而是一种思维模式。在高纬度层面对问题进行系统性分析,在低纬度层面将问题解构成具有层次性和逻辑性的多个部分进行封装统一管理,来达到降低复杂度和保证安全性的这么一个思维方式。
四、测试理解与实践的演进
1. Unit 1
由于第一次接触面向对象的作业,第一单元在架构设计和实现上花费了大量的精力和时间,并且没有搭自动评测机的经历,所以三次作业都是以手动测试为主,是基于模块化的测试。构造一些边界数据测试各个功能模块,包括解析、计算、化简,然后再统一进行数据测试。
2. Unit 2
第二单元已经开始接触自动化测试,我开始借鉴同学的数据生成器开始随机生成数据,虽然数据量和强度都很小,但也是有所收获。初步的功能性测试是依靠自动评测机实现,对于一些边界情况就得靠构造边界数据。
3. Unit 3
第三单元的数据构造和测试相对于前两个单元要简单不少,因为输入指令简单,所以可以采用大量的随机数据进行测试。我用python搭建了一个随机数据生成器和对拍机,用于和同学的代码进行大量的数据测试和对拍。同时,基于JML规格的逻辑性,虽然每个人实现代码不同,但是代码的逻辑分支都是相同的,于是,我和同学进行了代码上的对拍,来查看对JML理解的正确性。
4. Unit 4
第四单元并没有做太多的测试,因为代码逻辑并不复杂,最重要的是对作业指导书的理解,按照指导书的要求阅读代码找漏洞比较方便。
四个单元的测试主要分为基本的功能性测试和性能测试,前三个单元对功能性测试和性能测试都有比较高的要求,最后一个单元对性能测试的要求不高。我认为形式化验证是最好的测试方式,也是最耗费精力的方式。自动化随机测试有利于查找一般情况,及测试程序的请求压力。所以对于性能和基本功能测试可以采用大量的自动化随机测试,一些边界的情况还得根据代码进行数据设计。
五、课程收获
- 在第一单元认识了“类”、“接口”、“对象”等概念,学会了层次化的架构设计。
- 在第二单元进行了多线程的简单实践,学到了锁的机制和锁的利用。
- 在第三单元学到了规格化编程的思想。
- 在第四单元学习了UML图的相关知识。
此外:
- 熟悉并掌握了java基本语法和多种容器的使用。
- 通过阅读指导书提高了阅读理解能力以及将问题转化成代码的能力。
- 提升了测试能力。
- 提高了对作业的耐心和细心程度。这么课程虽然有些困难但是非常的有趣,每次作业的实现都是痛并快乐的过程。
- 复习或学习了很多算法,包括prim、并查集等图论算法。
六、课程建议
- 建议调整单元顺序,我认为可以将UML图的作业放在第一单元,不仅可以学习架构设计,还可以让同学有时间学习思考面向对象设计的理解,为后面的学习积累经验。因为本学期的表达式化简单元还是比较有难度的,大部分同学的时间都花在了作业的完成上,没有太多剩余的时间思考。
- 一个单元三次作业可以采用易、难、易或者易、难、难的难度设计,在第二次作业和第三次作业的迭代更加明显,让一些同学能够在第二次作业就能及时进行重构设计,避免让同学陷入第三次作业还要大量重构的尴尬境地。
- 可以设置一次作业来提高同学之间的合作与交流,即设计一次难度不大团队作业。