BUAA_OO 第四单元总结——UML
BUAA_OO 第四单元总结——UML
被OO爱(折磨)了一个学期,终于要结束了,真的有些感慨。回顾这些博客和代码,也真的难以想象自己竟然写了这么多,虽然过程很折磨,但是最后还是坚持了下了,虽然在一次次的作业中我出现了好几次的错误,最后的成绩可能不是那么好,但我还是收获了很多。当我自己真正的完成了架构设计并测试完毕之后(虽然测评机有时写的有点问题),总会有一种巨大的满足感产生。
本单元作业的架构设计
本单元采用增量式开发,但三次作业可以明显地划分为三个相对独立的部分,因此可以进行分别处理。
第一次作业
第一次作业要求实现UML类图解析器。
将UML类图进行解析的总体思路和解析器要求当然是采用了先建立结构再基于结构查询的方法,因此需要按照层次结构先进行解析。
我才用自顶向下依次解析的方法,首先将类图中涉及的所有元素分成三类:
UmlClass、UmlInterface
UmlGeneralization、UmlInterfaceRealization、UmlAttribute、UmlOperation
UmlParameter
根据需要,建立了MyClass,MyInterf,MyOperation
三个类,按照从属关系,分别把每个类的属性方法继承等等分别保存到相应的类中。
例如MyClass
类
private final ArrayList<MyClass> subClasses = new ArrayList<>();//子类
private MyClass fatClass = null;//父类
private final ArrayList<MyInterface> realItf = new ArrayList<>();//接口实现
private final ArrayList<MyOperation> umlOperations = new ArrayList<>();//操作
private final ArrayList<UmlAttribute> umlAttributes = new ArrayList<>();//方法
总的来说,建立对应类的原因为UML元素无法直接的将不同Element的层次关系直观地表达出来,因此需要建立对应的类模型来直接显示Element之间的从属关系。
此时查询对应的指令就可以到相应的类或者接口里面查找。
继承自其各级父类的操作
- 它是指对类进行查询时也需要考虑自身从父类继承的方法或者属性。
- 采用方法:递归法
- 解释:就是对当前自己的类中的指令查询完以后,通过父类的类或者接口再次查询,最后返回
Hashset
- 当我们在考虑递归时,通过返回值的方式在设计时无疑是较为困难的,因此我们在传递时增加传递参数来获得父类的所有属性或者操作
- 它还有另一个好处,那就是避免了重名问题
第二次作业
增加乐时序图和状态图,在莫种程度上和第一单元没啥联系。
设计架构:仍然是自顶向下的对UML图进行解析
顺序图
UML_INTERACTION
UML_LIFELINE、UML_ENDPOINT
UML_MESSAGE
状态图
UML_STATE_MACHINE
UML_REGIONMyInteraction
UML_PSEUDOSTATE、UML_STATE、UML_FINAL_STATE
UML_TRANSITION
UML_EVENT、UML_OPAQUE_BEHAVIOR
这次增加了顺序图和状态图,同时由于三种UML图不同,因此我建立了ClasModel、SeqModel、StateModel
来分别保存三种模型,在中模型里面分别进行架构。
顺序图
- 建立了
MyInteraction
来进行不同的UMLInteraction类
状态图
- 建立了
MyStateMachine、MyTransition
类
时序图与状态图的相关作业需求并不是很复杂,需要注意的地方是判断关键状态的那个地方,需要写好递归,并且注意条件
- 删除某个状态之后无法从 Initial State 到达任意一个 Final State,且不与后两条规定相悖,则该状态是关键状态;
- 如果状态机模型本来就无法从 Initial State 到达任意一个 Final State(包括 Final State 不存在的情况),则该状态机中所有状态都不是关键状态;
- Initial State 与 Final State 不是关键状态。
具体的代码如下
private boolean isReach(HashSet<String> visitList, String source, String forbid) {
visitList.add(source);
for (UmlFinalState finalState : finalStates) {
if (finalState.getId().equals(source)) {
return true;
}
}
for (MyTransition transition : transitions) {
if (transition.getSource().equals(source)) {
String target = transition.getTarget();
if (!target.equals(forbid) && !visitList.contains(target)) {
if (isReach(visitList, target, forbid)) {
return true;
}
}
}
}
return false;
}
第三次作业
第三次作业涉及模型的有效性检查,基本架构与第二次完全相同。
进行模型检查时我是直接将不同的检查代码分别分发到不同的模型中进行检查。
类图的检查
- 困难点在于对循环继承和重复继承的检查
- 循环继承
- 对于每个类或者接口,利用递归的方式将这个元素的所有父类保存起来,并保存他出现的次数,如果该类多次出现则循环继承
- 重复进程
- 同理,保存每个类的所有父类出现的次数,判断是否多次出现。
另外两个UML图比较好检查。
扩展
在我写完之后,我发现了一种更加代码节省的方法,那就是直接在一个类里面表示一种模型
具体实现:例如类图
对于每个非Class类的方法,在一个类图里面直接保存,保存方法为HashMap的方法,里面的元素为<ParentID,ArrayList<这种元素>>
,这样的保存方法可以使在查询某个类的方法时直接查询该HashMap即可。
不过这样理解起来确实没有分别建立关系直接明细。
四个单元中架构设计思维及OO方法理解的演进
第一单元
第一次作业还是尽可能的按照解决问题的流程和规范来实现的,而在后两次作业中,在设计架构上,根据表达式的层次化结构,将各种运算抽象出来,将各种运算门抽象为类,同时进行分层分析。最后实现完整的模型,感觉第一单元的主要主要考虑类的封装和继承关系,同时着重考察对数据进行提取和分别封装。
理解方面主要是对于整体表达式分解上的理解加深,主要是能从一个整体的角度去看待模型,而不是再像我第一次作业那样进行一些不符合表达式的优化。
第二单元
第二单元“电梯”的可扩展性越来越强了,感觉这个单元更像是以抽象性模型为基础的扩展,例如“生产者消费者”模型之类的,根据已知模型进行扩展。
这一单元最重要的线程安全设计,线程安全无疑是对于面向对象的一个很重要的概念,如何加锁而来保证理解资源的安全性十分重要。由于多线程的引入,设计重点从如何实现某个对象变成了如何考虑对象之间的交互。同时开放性的调度算法也让我们思考如何达到最优化。
理解方面主要是对于不同类之间的交互有了一个更层次的了解,同时也知道了线程安全的重要性(悲。设计上也就是根据生产者消费者模型的扩展。
第三单元
第三单元强调的更多的是规格化,让我体会到了在实际工程实现中根据规格要求实现具体方法的过程,我们的设计重点其实是根据JML来实现最简化的方法,因为JML表达的规格只是实现的结果和约束,但是具体的算法方面并不是最优化。在阅读JML时,我们要理解JML所表达的规格化设计深层化的设计方法,将需求抽象出来应用到实际。
第四单元
第四单元更像是层次化管理,将UML各层次在自己的代码中分离实现,建立自己的层架架构。
在设计时为了将各层次分离开而以免调造成混淆,因此我设计时建立了自己的UML层次结构,我自己建立的类并没有继承自官方所给的类,而只是把官方的类对象作为了我自己类的一个成员变量,由我的类提供查询接口,获得官方包信息。
在层次化的设计上,将各种UML中的元素分离分析,从抽象到具体的逻辑管理,理解UML图的本质,是十分重要的概念。
总结自己在四个单元中测试理解与实践的演进
我每个单元的测试风格都大差不大,在最开始都会采用一定的自己构造数据的方式来进行一定的测试,而在逐步加深理解中,我学会了生成自动测评机采用对拍的方式来进行处理。
第一单元采用了 Python + Sympy 作为数据生成和测试手段,同时手动构造边缘数据来测边界。
第二单元主要是基于Python的随机数据生成器进行大量轰炸,同时为了加快测试速度,采用了多线程。
第三单元我最开始用的是Junit来进行测试,后来发现这样构造数据具有局限性,最后还是采用数据生成器的方式。
第四单元一方面手动构造UML模型,另一方面利用了往届巨佬的Python模型生成器作为基础,进行对拍。
Hint:对拍是一个方便的过程,这样你直接减少了正确新测试的代码量
前提是对拍的人正确性能得到保障
总结自己的课程收获
熟练的使用了Java语言,学会了用Java语言进行一定规模的开发,学会了使用git进行版本管理,还进一步的巩固了Python(写数据生成时用),由于暑假进行了冯如杯的准备,导致一直没有放太多时间到课程上,导致开学时疯狂复习,才发现为了学习OO还需要进行这么多的准备工作。
第一单元学会了面向对象编程的封装继承多态的原理,加深了对递归思想的应用。
第二单元学会了多线程开发机制和安全性设计原则。
第三单元学会了规格化开发程序,理解了模型建构。
第四单元学习了UML的相关知识,进一步进行层次化设计。
研讨课上,通过交流能够碰撞思维的火花,不仅结交了友谊,还获得了需要创新性的思维,无论认识与否,当在一起讨论如何进行更优化设计的时候是一件很有意思的事情。
上机课则是对每个单元进行简单预习,当每次开一个新的单元时,如果仍对如何层次化设计不明白时,等到上机看看人家是怎么设计的无疑是一种更好的选择。
博客作业则非常有意思,能帮助我提高自己的表达能力,同时通过博客吸取经验,提升自己的思维方式,同时可以借鉴其他同学博客,取其精华,优势互补。好的博客和代码一样,能让人迅速的了解你,同时也能够展现自己的思维方式。
而OO整体的课程则是帮助我进行了从零开始的面向对象思维的学习,教会了一种认知方法,理解层次化,模型化,并发设计,对设计架构有了更好的认识。
当然这门课也提高了我自己的心态。
立足于自己的体会给课程提三个具体的改进建议
每周作业:建议提高一下弱测的强度,感觉弱测实在是有一点太弱了,希望能稍微强一点点就好。
增加预习环节:我真的觉得第一单元的作业实在是太难了,和后面三个单元的折磨程度完全不同,感觉预习的环节有点薄弱,每次在开新的单元的时候真的完全无法下笔。
减少第三单元内容?改成两次考试?因为感觉内容不太多,而且每次作业扩展的知识点也不太多。