两次UML解析程序,主要是递进式的,第一次解析了类图,第二次在类图基础上,增长检查规则和顺序图及状态图。java
整体架构思路主要有五点:算法
一、尽可能还原图自己的结构(组装)json
二、分类(状态图、顺序图、状态图)设计模式
三、元素与关系分离安全
四、对同一类element进行合并数据结构
五、抽象Element多线程
先从类图来说:架构
一、还原框架
每一个class有attribution、operationide
每一个operation有parameter
所以有
UMLPARAMETER-->UMLOPERATION + UMLATTRIBUTION -------> UMLCLASS
对接口有相似操做,继承Class便可
简单的画个类图他们关系大概就是这样
咱们只需经过json中的_parent和id就能够把他们联系这一块儿,至此重组完成。
针对第二次解析程序这里有一些小改变(元素重名检查):
因为类图检查须要检查Class对端的asscociationEnd与自身Attribution的重名问题。也就是说associationEnd也会属于Class,所以AbstractClass中的内容须要增长asscociationEnd的存放(只需增长一个容器和规则检查方法,总体难度不大,算是作了一次小拓展)
二、关系与元素分离
关系主要是类之间的,有继承、实现、关联。
因为UMLClass是咱们元素组装的最上层,天然关系与其同层次,放在任何一个里面都不太合适,所以选择了将他们分离的策略。
咱们单独创建一个Relation来存放他们。
解析json-->识别type-->分类存放 便可。
针对第二次解析程序这里有一些小改变(关系检查):
不管是循环继承的检查仍是重复继承的检查,都整合了这两种关系(继承、实现),所以为了操做方便,这里选择增长一个RelationCheck类,构建一个继承和实现关系构成的图。而后用上各类搜索方法(如DFS)就能够轻松解决上述检查。
由此能够看出,在这种架构之下,两次解析程序的递进针对类图都不会出现重构的状况,只需作少许拓展,便可完成。
再讨论下状态图吧
一、还原
跟类图同样,按照层次关系:(关系比类图要简单点)
UMLState + UMLTransition --> UMLReion --> UMLStateMachine
重组便可
public class AbstractStateMachine {
private String name;
private String id;
//Region
private String regionId;
// UMLTransition
private HashMap<String, UmlTransition> idToTranstion = new HashMap<>();
private HashSet<AbstractTrans> transHashSet = new HashSet<>();
//UMLState
private HashSet<AbstractState> states = new HashSet<>();
private HashMap<String, AbstractState> idToState = new HashMap<>();
private HashMap<String, ArrayList<String>> nameToState = new HashMap<>();
//RELATION
private HashMap<AbstractState, HashSet<AbstractState>> transRelation
= new HashMap<>();
private HashMap<AbstractState, Integer> idToSubCount
= new HashMap<>();
可能会发现Region怎么彷佛和State平级,主要是因为Region实在对查询功能无大用,更像是StateMachine的傀儡???
二、合并
这是我针对本次做业想重点讨论的话题。
也是我认为本次设计成功的点之一:为了易修改,易拓展而设计
State
状态机中有三类状态:UmlFinalState、UmlPseudostate、UmlState,状态统计须要考虑这三者,同时状态转移也是在这三者中进行,所以咱们能够采用一个AbstractState类来代替这三种。
public class AbstractState {
//0: state -1:init 1:final
private int type;
private String name;
private String id;
public AbstractState(int type, String name, String id) {
...
}
这样作有良好的可修改性,咱们能够自行定义,什么是共同状态?。
好比针对以前一直比较有争议的是否合并起始状态等问题,只需修改重写的equals方法便可。
一样,对Transiton也采用一样的方法。
package stategraph;
import java.util.ArrayList;
public class AbstractTrans {
private String id;
private String name;
private AbstractState source;
private AbstractState target;
private String guard;
private ArrayList<String> triggers;
public AbstractTrans(String id, String name, AbstractState source,
AbstractState target, String guard,
ArrayList<String> triggers) {
...
}
一样,什么是相同状态,咱们就能够在此定义,一旦规则有变,也只需修改这一处便可。(虽然最后限制了测试数据,这个地方没有了大用)
三、分离
在这里,相似于类图中的操做,把转移关系存储为图架构。须要注意的是,因为考虑了合并问题,所以能够经过一个类AbstractTrans来封装它,经过重写equals方法便可实现合并。
最后是最简单的顺序图:
顺序图整体比较简单。
一、还原
跟类图同样,按照层次关系:
UMLLifeline + UMLMessage ----> UMLInteraction
重组便可
public class AbstractInaction {
private String name;
private String id;
//UMLLifeline
private HashMap<String, UmlLifeline> idToLifeLine = new HashMap<>();
private HashSet<String> represent = new HashSet<>();
private HashMap<String, ArrayList<String>> nameToLifeLine = new HashMap<>();
//UMLMessage
private HashMap<String, UmlMessage> idToMessage = new HashMap<>();
//RELATION
private HashMap<String, Integer> messageIn = new HashMap<>();
...
}
二、关系与元素分离???
(1)Interation跟message是从属关系,不是同层次
(2)查询命令简单,无任何图算法相关操做
所以,这里不采用,只是加两个容器储存和统计一下便可
四个单元对OO的架构设计是从面向过程到面向对象的一个巨大的转变。
第一单元,设计之初过多考虑功能性问题,致使多项式求导的设计很是没有层次感(把因子,项等杂糅在一块儿,经过递归处理,这样很是不OO)
第二单元,电梯的设计主要是多线程的安全性问题。我遇到了比较大的困难,很差的架构致使了线程不安全的可能性增长。可是通过参考多线程各类设计模式,而且把电梯调度分部分考虑,架构有了必定提高,但代码杂糅的程度仍是比较高的。
第三单元,JML部分因为助教提供了一个大致框架,我也更多去思考设计的层面,总体的思路和结构都好转。
第四单元,UML是我考虑拓展性和架构设计优劣性最多的一次。更多注重下一次功能可否垂手可得增长的内容,而且在本身的debug和修改的过程当中,体会到了很是大的好处。
我认为OO设计一开始不能一味考虑算法(功能性)和AC的问题,更多应该聚焦在层次拆解。
以第四次单元为例
(1)设计的最终目的(交互,最高层)
(2)分为哪几个大部分(顺序图,状态图,类图)
(3)对每一个部分,有哪些小部分
主要考虑功能部分和元素部分
例如,状态图的元素有迁移、状态,功能是查询。
针对元素部分作适当有层次的封装(也就是充分展示类之间的继承关系,关联关系)
(4)采用什么样的数据结构??
(5)具体实现算法
其实,只要把(1)-(3)重点考虑(通常能够在纸上画出层次图(如使用UML))
(4)作必定考虑 (5)也就垂手可得了
综上所述
(1)思考和设计大于写码,好的层次必定程度上能让功能设计更加垂手可得。
(2)OO的设计是能帮助更好,更高质量的AC,若是一开始过度考虑AC,反而拔苗助长(惨痛教训)。
从最开始做业使用手动测试,到多项式的后两次做业开始尝试本身编写评测机制。
从固定结果的验证方法,到多线程不肯定性如何验证正确性的测试编写。
从整体的黑箱测试到Junit作单元测试
从测试正确性到测试运行时间。
上述,大概就展示了我OO中的测试思路的转变(几乎每一次转变都是爆掉几个点以后的痛定思痛)
我认为测试
(1)正确性和运行时间兼顾(保证明现的正确性和使用方法和结构的优良性)
(2)整体测试和单元测试兼顾(我后来采用了边编码边JUNIT的历程,不得不说,正确性更有保障)
(3)自动评测很是重要(利用随机样例去测试,经过较长时间的运行,保证黑箱测试的覆盖率问题)
2、抗压能力:屡次临dll修改bug,有成功修改,有不成功修改的,这样的经历确实很是锻炼在短期的修改代码并保证正确的能力。
3、需求分析能力:对指导书的内容进行分析,而且逐渐转化为程序语言。
4、还有对OO的理解和承认,对测试的体会,都是此次的巨大飞跃。
1、建议课程组提供自主测试平台:本次测试和评测机测试存在运行时间上的偏差,所以建议给你们开放一个平台,让全部人均可以在上面进行测试,获得运行时间,对多线程以及卡TLE的部分做业很是有帮助。
2、上机内容能够考虑提早发布一些预习任务,这样能让上机时候更加有针对性去应对,不至于手足无措。
3、适当预告后续做业的需求:有利于更好的拓展性设计。