OO UML总结暨课程总结

OO UML总结暨课程总结

一、架构分析

两次UML解析程序,主要是递进式的,第一次解析了类图,第二次在类图基础上,增加检查规则和顺序图及状态图。

总体架构思路主要有五点:

1、尽量还原图本身的结构(组装)

2、分类(状态图、顺序图、状态图)

3、元素与关系分离

4、对同一类element进行合并

5、抽象Element

 

先从类图来讲:

1、还原

每个class有attribution、operation

每个operation有parameter

因此有

UMLPARAMETER-->UMLOPERATION + UMLATTRIBUTION -------> UMLCLASS

对接口有类似操作,继承Class即可

简单的画个类图他们关系大概就是这样

 

我们只需通过json中的_parent和id就可以把他们联系这一起,至此重组完成。

 

针对第二次解析程序这里有一些小改变(元素重名检查):

由于类图检查需要检查Class对端的asscociationEnd与自身Attribution的重名问题。也就是说associationEnd也会属于Class,因此AbstractClass中的内容需要增加asscociationEnd的存放(只需增加一个容器和规则检查方法,整体难度不大,算是做了一次小拓展)

 

2、关系与元素分离

关系主要是类之间的,有继承、实现、关联。

由于UMLClass是我们元素组装的最上层,自然关系与其同层次,放在任何一个里面都不太合适,因此选择了将他们分离的策略。

我们单独建立一个Relation来存放他们。

解析json-->识别type-->分类存放 即可。

 

针对第二次解析程序这里有一些小改变(关系检查):

无论是循环继承的检查还是重复继承的检查,都整合了这两种关系(继承、实现),因此为了操作方便,这里选择增加一个RelationCheck类,构建一个继承和实现关系构成的图。然后用上各种搜索方法(如DFS)就可以轻松解决上述检查。

 

由此可以看出,在这种架构之下,两次解析程序的递进针对类图都不会出现重构的情况,只需做少量拓展,即可完成。

 

再讨论下状态图

1、还原

跟类图一样,按照层次关系:(关系比类图要简单点)

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的傀儡???

2、合并

这是我针对本次作业想重点讨论的话题。

也是我认为本次设计成功的点之一:为了易修改,易拓展而设计

 

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) {
      ...
  }
   
   @Override
   public boolean equals(Object obj) {
       if (obj != null && obj instanceof  AbstractState) {
          ...
      }
       return false;
  }
   
   @Override
   public int hashCode() {
       return type;
  }
  ...
}
   

这样做有良好的可修改性,我们可以自行定义,什么是共同状态?。

比如针对之前一直比较有争议的是否合并起始状态等问题,只需修改重写的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) {
      ...
  }
   
   @Override
   public boolean equals(Object obj) {
       if (obj != null && obj instanceof  AbstractTrans) {
          ...
          }
           return false;
      }
       return false;
  }
   
   @Override
   public int hashCode() {
       return 1;
  }
 
  ...
}

同样,什么是相同状态,我们就可以在此定义,一旦规则有变,也只需修改这一处即可。(虽然最后限制了测试数据,这个地方没有了大用)

 

3、分离

在这里,类似于类图中的操作,把转移关系存储为图架构。需要注意的是,由于考虑了合并问题,因此可以通过一个类AbstractTrans来封装它,通过重写equals方法即可实现合并。

 

最后是最简单的顺序图

顺序图总体比较简单。

1、还原

跟类图一样,按照层次关系:

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<>();
  ...
}

2、关系与元素分离???

(1)Interation跟message是从属关系,不是同层次

(2)查询命令简单,无任何图算法相关操作

因此,这里不采用,只是加两个容器储存和统计一下即可

 

二、架构设计总结及OO方法理解的演进

四个单元对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)自动评测非常重要(利用随机样例去测试,通过较长时间的运行,保证黑箱测试的覆盖率问题)

 

四、课程收获

1、编码能力:通过本学期十多次作业的练习,作业的规模让自己的代码能力显著提高。

2、抗压能力:多次临dll修改bug,有成功修改,有不成功修改的,这样的经历确实非常锻炼在短时间的修改代码并保证正确的能力。

3、需求分析能力:对指导书的内容进行分析,并且逐渐转化为程序语言。

4、还有对OO的理解和认可,对测试的体会,都是这次的巨大飞跃。

五、建议

1、建议课程组提供自主测试平台:本次测试和评测机测试存在运行时间上的误差,因此建议给大家开放一个平台,让所有人都可以在上面进行测试,得到运行时间,对多线程以及卡TLE的部分作业非常有帮助。

2、上机内容可以考虑提前发布一些预习任务,这样能让上机时候更加有针对性去应对,不至于手足无措。

3、适当预告后续作业的需求:有利于更好的拓展性设计。

 

转载于:https://www.cnblogs.com/thunderZH-buaa/p/11075303.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值