终于到了令人愉快的暑假最后一个单元啦,在完结撒花之前,让我们先来完成这最后一次轻松的OO的博客作业。
第四单元总结
第四单元的核心内容就是UML的一些基本处理,这个阶段的作业跨度相对前面几个单元较长(也非常感谢贴心的OO助教和老师们考虑到我们考试的原因予以延期),所以我们有了充足的时间去理解这次作业的一些有关内容。
其实有关UML的知识其实很多,在简单的查阅资料后我发现它能够体现的类之间的关系并不只是有我们作业所涉及的继承(Generalization)、实现(Realization)和关联(Association),还包括了依赖、聚合、组合等关系,但是为了贴近这个单元的两次作业,所以在这篇博客中我仅仅就两次作业中涉及到的点来进行说明和讲解,若有不当或失实之处,还望老师和同学们予以指正。
一、涉及到的工具
这个单元我们主要利用的工具就是StarUML,我们可以利用这个画图软件工具来绘制我们希望实现的类或者接口之间的关系,而并不需要自己挖空心思去写代码考虑架构,然后就可以结合作业给出的jar包并利用cmd来将我们绘制好的类图导出成本次作业使用的标准输入格式,来对我们的代码加以测试,可以说功能已经是非常的清晰和完善了。
当然StarUML并不仅仅可以用来画类图,第二次作业涉及到的状态图和顺序图也都可以一并用它绘制出来,具体的操作就是点击Model下的Add Diagram,对于状态图我们新建一个Statechart Diagram即可,对于顺序图我们选择Sequence Diagram即可。
同时它还有一个很方便的功能,那就是绘制已经写好的java代码的类图,操作同样很简单,在安装java插件之后,选择Tools->java->Reverse Code...,然后直接选中整个java工程即可。
当我们掌握了正确使用这项工具的姿势后,我们就可以很轻松愉快的开启第四单元的作业之旅啦。
二、两次作业的设计
(1)第一次作业
其实第一次作业我的大部分时间都花在了一件事情上,那就是读源码,虽然不知道为什么直接复制开源包的源码到工程里没办法编译通过,但是对于源码中关于element的部分我却丝毫不敢疏忽,因为这是整次作业做关键的地方。
在一开始写代码的时候我做了一件非常愚蠢的事情,那就是单纯地把读取到的所有元素都当做UMLElement来处理,但是后来我发现这样做的后果是我不知道怎么样获取不同种类的元素对应的属性,例如AssociationEnd的source和target等。于是我开始怀疑自己代码书写方式的正确性,便去阅读源码,果然我发现了在众多的UML类型中,UMLElement是一个顶级类,其他的类都是作为子类继承了这个类,我们只需要简单的进行一个类型转换,便可以对子类中的一些方法进行访问。在解决了这个问题之后,这次作业留给我的问题就已经为数不多了。
在第一次作业中我们一共要实现九条指令,而其中绝大多数的指令都是进行简单的计数,例如获取类操作数量,只需要在输入的时候将所有的类提取出来,再将所有的操作(Operation)提取出来,根据类的ID和操作的ParentID进行匹配,最后计数即可,但是在这里,部分指令需要考虑到子类继承父类的情况,写法也并不难,其余几条类似的指令也是同样的过程。
在整个第一次作业中最为复杂的一条指令也是最容易出错的一条指令就是获取实现的接口列表了,虽然一个类只能继承一个类,或者实现一个接口,但是接口是可以多继承的,所以计算起来很容易出现重复计算或者漏算的情况,在这里我使用了如下的算法,先贴上代码:
1 /** 获取实现的接口列表CLASS_IMPLEMENT_INTERFACE_LIST*/ 2 public List<String> getImplementInterfaceList(String className) 3 throws ClassNotFoundException, ClassDuplicatedException { 4 if (!nameList.containsKey(className)) { 5 throw new ClassNotFoundException(className); 6 } else if (nameList.get(className) > 1) { 7 throw new ClassDuplicatedException(className); 8 } else { 9 UmlClass classFound = getClassByName(className); 10 HashSet<UmlInterface> list = new HashSet<>(); 11 getInterList(classFound, list); 12 ArrayList<String> list1 = new ArrayList<>(); 13 for (UmlInterface key : list) { list1.add(key.getName()); } 14 return list1; 15 } 16 } 17 18 private HashSet<UmlInterface> getInterList( 19 UmlClass classFound, HashSet<UmlInterface> list) { 20 UmlClass son = classFound; 21 addInterList(son, list); 22 while (!sonToFather.get(son).equals(son)) { 23 son = sonToFather.get(son); 24 addInterList(son, list); 25 } 26 return list; 27 } 28 29 private HashSet<UmlInterface> addInterList( 30 UmlClass son, HashSet<UmlInterface> list) { 31 for (int i = 0; i < classToInter.get(son).size(); i++) { 32 UmlInterface inter = classToInter.get(son).get(i); 33 list.add(inter); 34 getFather(inter, list); 35 } 36 return list; 37 } 38 39 private HashSet<UmlInterface> getFather( 40 UmlInterface inte, HashSet<UmlInterface> list) { 41 for (int i = 0; i < interSonToFa.get(inte).size(); i++) { 42 list.addAll(interSonToFa.get(inte)); 43 } 44 if (interSonToFa.get(inte).size() == 0) { return list; } else { 45 for (int i = 0; i < interSonToFa.get(inte).size(); i++) { 46 getFather(interSonToFa.get(inte).get(i), list); 47 } 48 return list; 49 } 50 }