BUAA_OO_第四单元作业总结及课程总结
第四单元作业总结~课程总结
BUAA OO 2021面向对象作业
19373469 陈纪源
一、本单元作业设计架构
(一)第一次作业
第一次作业主要是梳理UML的原理,正确理解UML模型之间的关系。
第一次主要是基于对类图的分析,因此是主要分析类和接口等元素的关系。
通过分析实验课代码,可以得到UML模型架构如下所示。
最顶层元素是UmlClass和UmlInterface,相当于图中的点,而图中的边则是UmlGeneration和UmlInterfaceRealization,分别表示类与类之间的继承关系和类与接口之间的实现关系。之后类与接口有UmlOperation,表示类和接口中的操作。而类自己还有UmlAttribute,表示类自己的属性。而UmlOperation下面还有UmlParameter表示类的参数(包括返回值),而这些所有的类都通通继承UmlElement类。
通过对Uml模型的架构梳理,我建立了自己的MyUml类。(这里原因有两个,一个是通过实现自己的MyUml类可以更好的对功能进行扩展;另一方面,是因为官方接口的Uml模型的构造函数是private的,是无法在外部构建的,因此我采用构建自己MyUml类。
以下面的MyUmlClass为例。
public class MyUmlClass {
private UmlClass umlClass = null;
......
public MyUmlClass(UmlClass umlClass) {
this.umlClass = umlClass;
}
public UmlClass getUmlClass() { return umlClass; }
......
}
我的每一个自己实现的MyUml类,通过关联对应的Uml类,可以做到对Uml类的管理。
同时我还实现了一个DataManagement类,里面包含两部分内容,一部分是从id到UmlElement的映射,另一部分则是Uml类到MyUml类的映射,如下图为例。
public class DataManagement {
private static TreeMap<String, UmlElement> idToUmlElement = new TreeMap<>();
private static HashMap<UmlClass, MyUmlClass> classHashMap = new HashMap<>();
public static void addUmlElement(UmlElement element) {
String id = element.getId();
idToUmlElement.put(id, element);
}
public static UmlElement queryFromIdToElement(String id) {
if (idToUmlElement.containsKey(id)) {
return idToUmlElement.get(id);
} return null;
}
public static void addMyUmlClass(MyUmlClass myUmlClass) {
classHashMap.put(myUmlClass.getUmlClass(), myUmlClass);
}
public static MyUmlClass getMyUmlClass(UmlClass umlClass) {
if (classHashMap.containsKey(umlClass)) {
return classHashMap.get(umlClass);
} return null;
}
......
}
管理容器和方法都是static静态方法,因此可以在外面直接调用和使用。
通过这种对数据的管理,可以很方面的做到了Uml类到MyUml类的一一映射了。
之后是Uml类图的分析了,算法方面主要采用的是遍历(即暴力)和记忆化搜索,记忆化搜索主要应用的函数是类实现的全部接口,通过hashSet进行去重来保证复杂度。
(二)第二次作业
第二次增加了顺序图和状态图,因此需要仔细考虑新增加元素之间的关系。
首先是顺序图,最上方的一层是UmlInteraction,下面一层是UmlLifeline,再下方是UmlMessage。
接下来是状态图,最上方的一层是UmlStateMachine,接下来是UmlRegion,下面接下来是UmlState,每个状态有UmlTransition。
仿照上一次作业对这些类进行数据管理,并分别建立对应的MyUml类。
接下来就可以对Uml类图分析的方法与第一次作业类似,使用遍历即可。
(三)第三次作业
第三次作业相比于前两次作业的内容增加了非法类图的判断。由于我前两次作业的类图、顺序图和状态图的所有元素都是在一块的,因此导致主函数的内容十分长,非常不面向对象,因此在这单元我对架构进行了部分重构。对于类图、顺序图和状态图分别使用三个类来管理,每次询问时从对应类的方法中询问。同时使用单粒模式来管理三种图,下面是本次架构的类图(省略了方法)。
下面对类图中的几个主要类进行分析。
Main是整个程序的入口。
MyUmlGenerallteraction是交互入口,它首先把所有UmlElement输入,之后把它们分散到MyUmlCollaborationDiagram、MyUmlStateDiagram、MyUmlClassDiagram中,分别建立不同的Uml图。同时它还需要对不合法的Uml类图进行判断,具体是把八种不合法情况分散到各个图中,之后使用图中的方法判断。维护的数据为所有输入的Uml元素。
MyUmlCollaborationDiagram是协作图类,管理协作图的数据。里面包括的数据为所有的MyUmlIntarction和输入的Uml元素。维护输入Uml元素的目的是方便建立协作图的这个结构(即Interaction-lifeline)。
MyUmlInteraction是协作图中的交互对象类,管理交互对象。里面包括的数据为所有对象包括的MyUmlLifeline,即对象所在的生命线。
MyUmlLifeline是生命线类,管理生命线。里面包括的数据是生命线之间传递的MyUmlMessage,即生命线之间传递的消息。
MyUmlStateDiagram是状态图类,管理状态图。里面包括的数据为所有对象包括所有的MyUmlRegion和输入的Uml元素。维护输入Uml元素的目的是方便建立协作图的这个结构(即StateMacine-Region-State/PseudoState-Transition)。
MyUmlRegion是状态机画布类,管理画布。里面包括的数据为所有状态机中的状态(包括起始状态和正常状态)。
MyUmlState是状态类,管理状态机中的正常状态。里面包括的数据为所有的转移状态。
MyUmlPseudoState是起始状态类,管理起始状态。里面包括的数据为起始状态。
MyUmlTransition是转移状态类,管理转移状态。里面包括的数据为触发事件。
MyUmlClassDiagram是类图管理类,管理类图。里面包括的数据为所有的类和关系。
MyUmlClass是类图类,表示单一的类图。里面包括的数据为当前的类的父类,包含的操作、属性、接口。
MyUmlAssociation是关系类,表示类图或者接口之间的关系。包括两个关系的两个端口。
MyUmlOperation是操作类,表示类图或接口包含的操作。里面包括操作的名称和个数。
MyUmlInterace是接口类,表示单一的接口。里面包括能到达的所有接口的集合。
DataManagement数据管理类,表示管理的所有数据,包括了所有的id到Uml类的映射和所有的Uml到MyUml的映射。
将输入的元素分散到各个图中(类图、协作图、状态图),通过各个图中包含的方法进行交互。
对于求一个接口能到达的所有接口,这里采用的是dfs和记忆化的方式(通过先排除有环的情况)来完成的。
二、总结自己在四个单元中架构设计及OO方法理解的演进
第一单元
-
第一单元架构主要是运用递归下降法对表达式进行了解析,之后采用表达式树对表达式、因子进行管理,最后调用统一的求导方法。
-
认识到规格化设计的重要性,通过使用继承类或接口抽象的对数据进行管理,减小重复的方法,统一管理。
-
认识到架构设计的重要性,好的架构是成功的一半。
-
一定要让各个类要做到解耦合,每个类干自己的工作。
第二单元
- 第二单元架构是多层生产者消费者模式,需求通过全局队列交给调度器,调度器根据各个电梯当前的容量及运行状态将内容分散到局部电梯当中去。
- 认识到封装的重要性,好的电梯应该是策略与行为分开的。
- 好的架构可以避免出现线程安全问题(问题)。
第三单元
- 第三单元架构是根据所给JML写出一个社交网络模型,需要注意的是性能问题。
- 认识到JML规格只是对我们的需求的一个约束,真正的实现需要我们自己去设计架构。
- 对于规格化编程、契约化编程有了一个更加清醒的认识,意识到这种编程的重要性,对于封装有很大的帮助。
第四单元
- 第四单元架构是根据UML本身的结构写了一个UML解析器。
- 认识到UML本身的架构非常优秀,也通过理解UML本身的架构更加理解了好的层次化结构的重要性。
- 学习到单例模式的意义。
- 认识到高内聚,低耦合的重要性。
三、总结自己在四个单元中测试理解与实践的演进
第一单元
第一单元的表达式求值,测试时采用python的包。通过大正则随机生成表达式,将java输出与python输出相对比进而得到对拍结果。
主要采用随机测试,通过大量的数据覆盖对表达式进行了覆盖。
实践时主要问题在于第一单元的大正则表达式,由于当时对正则表达式的理解不够深刻,导致出现爆栈的问题。在意识到大正则的严重性问题后,我采用了递归下降重构了架构(但其实重构的非常痛苦),后来发现表达式树做为一个良好的架构可以很好的进行统一处理,因此最终使用表达式树处理了第二、第三次作业。
第二单元
第二单元的测试比较麻烦,本人没有好的办法,因此只能采用本地同一组数据多次测试,看程序是否有问题。
实践时主要难点时刚刚接触到多线程,锁和临界区的问题,死锁问题难度较大,因此在第一次写作业时虽然参考了实验课代码但依旧很痛苦。在第二次作业之前由于做了一次研讨课,明白了第一次作业的架构,因此更好的理解了多线程,对第二次、第三次作业有了较大的帮助。
第三单元
第三单元的测试主要采用和其他同学对拍的方式,JML数据主要通过随机产生,一些特殊的卡最短路的点需要使用特殊构造。
实践时主要难点在于对于JML规格的理解和一点架构的设计,包括最短路算法的使用,实践过程中基本没有遇到太大的问题。
第四单元
第四单元的测试还是采用对拍+手动构造的方式,UML数据采用部分随机,剩下在第三次作业卡合法性时要使用starUML手动构造。
实践时主要难点在于UML模型的理解和整个解析器的架构,前两次作业由于过于面向对象导致交互类主函数太长,因此于第三次进行了重构,形成了三种不同图的分别管理,采用单例模式,形成了一个良好的架构。
但是第三次作业需要考虑的情况数量非常多,因此最后在debug时花了大量的时间。
四、总结自己的课程收获
- 通过pre和第一单元的学习,从JAVA入门了。
- 通过第一单元的学习,学会使用正则表达式处理匹配问题
- 通过第二单元的学习,学习如何使用多线程处理问题
- 通过第三单元的学习,学习JML规格的使用和理解
- 通过第四单元的学习,学习UML模型和各种图结构
- 通过四个单元的迭代学习,对面向对象的内容有了更深刻的理解。
- 高内聚,低耦合
- 学习到了好的架构是成功的一半,在编程前一定要对架构进行良好的设计
- 提高了自己的码量
五、立足于自己的体会给课程提三个具体改进建议
- 第二单元多线程对于我来说难度梯度太大了,对于一个之前从来没接触过多线程的人,感觉离谱。希望课程组能提早渗透相关知识,可以在pre或者第一单元研讨进行知识渗透。
- 由于自己第一单元的时候明显感受到架构的重要性,而好的架构是成功的一半,但设计一个好的架构需要很大的难度,能否在某一个时间点(比如周六晚上)给一些架构提示,这样可以更好的帮助进度靠后的同学一些帮助。
- 第二单元的互测机制非常不合理,很多同学可以在本地复现bug,但交上去就无法复现。能否一个测试点测5-10次,只要出现错误就按照错误算。
六、感谢
- 感谢面向对象的构造与设计课程组准备的礼物,还是很喜欢的(不过精益求精奖难道不是公开处刑吗?)
- 感谢助教和老师们在这一个学期的辛勤付出。