任务要求:完成对UML的mdj文件的解析以及分析查询功能,通过此来获得对UML模型、类图、顺序图、状态图的一定的理解。
第一次作业:实现一个UML类图分析器,学习目标为UML入门级的理解、UML类图的构成要素及其解析方法。
第二次作业:扩展程序,实现对UML顺序图和UML状态图的解析。
第三次作业:扩展功能,对模型进行有效性检查。
二、第四单元作业架构设计
第一次作业
第一次作业只有类图,需要通过解析类图中的9种模型完成模型的构建。对此,我创建了类MyTree
用于解析传进来的elements并对其分析,并进行元素之间的关系构建。对于9种模型,我对于其中必要的模型进行了封装。比如对于元素UmlClass
,我创建了类MyClass
对其进行封装,在内部完成了对某个类的Attribute、Operation、所关联类等数据进行了保存和维护。这有些类似于适配器模式。
程序的大体流程是:首先将elements全部传入MyTree
中,在其构造方法内用switch语句进行分类,调用parse方法进行分析,构建模型。而查询时UmlInteraction
类中的方法可以直接调用MyTree
中的数据进行查询。
关于数据的保存,基本原则是查询用HashMap
, 遍历ArrayList
, 需要不能重复的时候用HashSet
;如果都需要的话就都用。
第二次作业
与第一次作业的差别在于加入了顺序图和状态图,多了很多东西,但写起来基本没有区别(就是很麻烦)。
我为状态图和顺序图额外分别创建了解析模型和保存数据的类MyStateTree
和MyCollaborationTree
,与MyClassTree
功能和结构一致。
在UmlGenerallInteration
中的查询方法中,只要与父类或者实现或继承接口相关的,我都用bfs进行实现,其中最有代表性的是方法getSubsequentStateCount(String s, String s1)
:
1 int num = 0;
2 Queue<MyGeneralState> queue = new LinkedList<>();
3 HashSet<MyGeneralState> marked = new HashSet<>();
4 HashSet<MyGeneralState> temp = state.getToStates();
5 if (!temp.isEmpty()) {
6 for (MyGeneralState generalState : temp) {
7 queue.offer(generalState);
8 marked.add(generalState);
9 num++;
10 }
11 }
12 while (!queue.isEmpty()) {
13 MyGeneralState tmp = queue.poll();
14 HashSet<MyGeneralState> nexts = tmp.getToStates();
15 if (!nexts.isEmpty()) {
16 for (MyGeneralState next : nexts) {
17 if (!marked.contains(next)) {
18 queue.offer(next);
19 marked.add(next);
20 num++;
21 }
22 }
23 }
24 }
25 return num;
另外值得一提的是,由于pseudostate
,finalstate
,和state
基本上没有区别,可以一起处理,我构建了抽象类MyGeneralState
来统一管理这三个种状态。
此外,对于抛出相同名字元素或者没找到名字元素的异常处理,我认为我也实现得非常巧妙,例如对于ClassNotFoundException
和 ClassDuplicatedException
,我在MyClassTree
中实现了方法:
1 public int sameNameClass(String name) {
2 int num = 0;
3 int index = 0;
4 for (int i = 0; i < classList.size(); i++) {
5 if (name.equals(classList.get(i).getClassName())) {
6 index = i;
7 num++;
8 }
9 if (num == 2) {
10 return -2; //repeated class
11 }
12 }
13 if (num == 0) {
14 return -1; //class not found
15 }
16 return index;
17 }
可以看出,在找到类的时候,返回的是该类在所有类的容器ClassList
中的下标,而未找到或重复时则返回负数异常值(跟OS实验学的)。这样做可以避免在做某项查询时,先判断名字重复异常遍历一遍,用名字找对应的类再遍历一遍。因此提高了效率。
第三次作业
第三次作业主要增加了有效性检查,整体架构完全不用改变,只需要增加几个函数即可。在此我放出最后这次作业的度量分析。
可以看出功能主要分散在三个Tree和总接口,整体结构还是合理的。
二、架构设计和OO方法演进
架构设计
实话实说,我个人认为对于架构设计而言,第一单元是我做得最出色的一个单元,因为混合求导是真正需要一个好的架构的任务。我认为在第一单元我的收获是最大的,真正理解了OO的很多核心概念比如继承和实现,并能运用其解决问题。
第二单元的多线程电梯我觉得更多的是练习了多线程的同步互斥等复杂问题,并没有太多架构设计。而第三单元我真的没感觉自己有什么收获,跳过。
第四单元和第一单元有点像,但没有太多整体的架构设计,而是一些小的,局部的架构设计,比如类的统一管理,功能分散式的设计等等。我认为除了对UML的理解之外,第四单元更像是对第一单元的一个复习。
OO方法
对于OO方法,架构就不说了,多线程的问题还是很有意思的,收获颇丰。规格设计我实在没搞懂,上课也基本听不明白。UML模型还好,上课同样完全听不懂,基本靠作业才能对模型有所理解。
测试
接触了主要的黑箱测试,以及一些简单的Junit单元测试,甚至测试驱动开发的方法。就我个人而言还是黑箱测试最好用,剩下的基本不会用,单元测试也觉得不好用很麻烦。黑箱测试随机生成数据比较无脑粗暴,还可以用来进行互测,非常的方便。
我的这种喜好也许是因为我太菜了吧。
三、课程收获
-
显而易见的,熟悉 Java语法,较为熟练的实用IDEA。
-
综合的软件能力,对于了解需求、根据需求设计、实现、测试的整个流程有了一个较为深入的理解。
-
OO基本方法和架构设计的能力,抽象设计的思维。
-
多线程编程初步入门。
-
UML图有一定了解(还是不知道有什么用)。
四、课程建议
-
第一单元难度过大。我相信不只有我一个人,很多人都会感觉第一单元的作业难度是最大的(当然对我来说也是收获最大)。可以适当下调难度。
-
上课听不明白。有时候老师的用词太模糊太抽象,例如讲规格那个单元,有非常多很抽象的概念,很多时候觉得不知所云,希望可以多注重抽象概念的阐释,可以多举一些例子。
-
希望实验可以有反馈。
线上学习体会