BUAA_OO第四单元总结性博客作业

一、三次作业简单介绍

第十三次作业:

实现一个 UML 类图解析器 UmlInteraction

本次作业最终需要实现一个UML类图解析器,可以通过输入各种指令来进行类图有关信息的查询。

实现指令:

模型中一共有多少个类 CLASS_COUNT
类中的操作有多少个 CLASS_OPERATION_COUNT classname mode
类中的属性有多少个 CLASS_ATTR_COUNT classname mode
类有几个关联 CLASS_ASSO_COUNT classname
类的关联的对端是哪些类 CLASS_ASSO_CLASS_LIST classname
类的操作可见性 CLASS_OPERATION_VISIBILITY classname methodname
类的属性可见性 CLASS_ATTR_VISIBILITY classname attrname
类的顶级父类 CLASS_TOP_BASE classname
类实现的全部接口 CLASS_IMPLEMENT_INTERFACE_LIST classname
类是否违背信息隐藏原则 CLASS_INFO_HIDDEN classname

第十四次作业:

在上次作业基础上,扩展解析器,使得能够支持对 UML 顺序图和 UML 状态图的解析,并能够支持几个基本规则的验证。

实现指令:

给定状态机模型中一共有多少个状态 STATE_COUNT statemachine_name
给定状态机模型中一共有多少个迁移 TRANSITION_COUNT statemachine_name
给定状态机模型和其中的一个状态,有多少个不同的后继状态 SUBSEQUENT_STATE_COUNT statemachine_name statename
给定UML顺序图,一共有多少个参与对象 PTCP_OBJ_COUNT umlinteraction_name
给定UML顺序图,一共有多少个交互消息 MESSAGE_COUNT umlinteraction_name
给定UML顺序图和参与对象,有多少个incoming消息 INCOMING_MSG_COUNT umlinteraction_name lifeline_name
R001:针对下面给定的模型元素容器,不能含有重名的成员(UML002)
R002:不能有循环继承(UML008)
R003:任何一个类或接口不能重复继承另外一个接口(UML009)

关键点 1 —— UML 规则:

准确理解 UML 规则,然后使用 Java 来实现相应的接口。

关键点 2 —— 架构设计:

  第一次作业和第二次作业紧密相关,要考虑好可扩展性。

二、UML 设计

三、两次次作业的类图与度量分析

度量分析标识:

    • ev(G)  本质复杂度
    • iv(G)   设计复杂度
    • v(G)   循环复杂度
    • OCavg  平均方法复杂度
    • OSavg  平均方法语句数(规模)
    • WMC  加权方法复杂度
    • v(G)avg 平均循环复杂度
    • v(G)tot 总循环复杂度

第十三次作业:

1、架构构思:

  第一次作业主要是继承 UmlInteraction 接口,实现相应的方法。

  我的设计是首先在 MyUmlInteraction 进行构造,读取所有的元素,然后在 Find 里用 HashMap 进行存储, MyAssociationMyInterfaceRealitionMyGeneralization 等直接查找好相应的类和接口,直接保存,方便查找。

  同时在 Cahce 里设置缓存,记录重复信息和每次查询后结果的存储,保证不做重复查找,提高效率。
Realiton 负责继承、接口实现、关联这些关系的存储。

  然后 MyUmlInteraction 中的每条指令都归类到相应的结构中,互不影响,例如:

getClassOperationCount Find.getClassByName(className).getOperationCount(queryType)**
getClassAttributeCount Find.getClassByName(className).getAttributeSize()
getClassOperationVisibility Find.getClassByName(className).getOperationVisibility( operationName)
getTopParentClass Find.getClassByName(className).getTopFatherName()

  其中 Find.getClassByName(className) 得到是 MyClass ,在这个类中包含相应的属性:

private UmlClass umlClass;
private HashMap<String, UmlAttribute> attributeNameMap;   
private HashMap<String, MyOperation> operationIdMap;    
private HashMap<OperationQueryType, Integer> operaCountMap;
private HashMap<String, HashMap<Visibility, Integer>> operaVisiMap;
private LinkedList<MyClass> fatherList;
private LinkedList<AttributeClassInformation> attributeInformationList;
private HashSet<String> interfaceIdSet;
private int assoicationCount;
private HashSet<String> assoicationIdSet;

​ 类似的, MyInterfaceMyOperation 也是一样。

2、项目分析:

类图分析:

度量分析:


3、自我总结:

  从 Metrics 的分析来看,这次作业的复杂度飘红是在 MyUmlInteraction.buildMapMyAssociation.add
  MyUmlInteraction.buildMap 是构造函数的一部分,我用了一个 forswitch 结构进行分类,提高了复杂度。

for (UmlElement uml : elements) {
    Find.addId(uml);
    switch (uml.getElementType()) {
        case UML_CLASS:
            Find.addClass(uml);
            break;
        case UML_INTERFACE:
            Find.addInterfaceId(uml);
            break;
        case UML_GENERALIZATION:
            generalizationList.add((UmlGeneralization) uml);
            break;
        case UML_INTERFACE_REALIZATION:
            Relation.addInterfaceRealition(uml);
            break;
        case UML_OPERATION:
            operationMap.put(uml.getId(), new MyOperation(uml));
            break;
        case UML_ATTRIBUTE:
            attributeList.add((UmlAttribute) uml);
            break;
        case UML_PARAMETER:
            parameterList.add((UmlParameter) uml);
            break;
        case UML_ASSOCIATION:
            associationList.add((UmlAssociation) uml);
            break;
        default:
            break;
    }
}

  而 MyAssociation.add 是因为我分别判断了两个 End 相同和不同的情况,每个情况又去添加相应的元素。

if (!contains(id1)) {
            associationEnd.put(id1, new HashSet<>());
        }
        associationEnd.get(id1).add(Find.getById(a.getEnd2()));
        if (!contains(id2)) {
            associationEnd.put(id2, new HashSet<>());
        }
        associationEnd.get(id2).add(Find.getById(a.getEnd1()));
        if (id1.equals(id2)) {
            if (Find.containsClassId(id1)) {
                if (!containsClass(id1)) {
                    associationClass.put(id1, new HashSet<>());
                }
                associationClass.get(id1).add(id1);
            }
        } else {
            if (Find.containsClassId(id1) && Find.containsClassId(id2)) {
                if (!containsClass(id1)) {
                    associationClass.put(id1, new HashSet<>());
                }
                associationClass.get(id1).add(id2);
                if (!containsClass(id2)) {
                    associationClass.put(id2, new HashSet<>());
                }
                associationClass.get(id2).add(id1);
            }
        }

  其他方法的复杂度都得到了有效的控制。

4、程序 bug 分析:

  这次出现了一个 bug,是因为我在存储 class 的时候,直接将同名的 class 覆盖了,导致当查询子类继承父类的属性时,查找到的那个类不是它真正的父类,后来我改为用 id 查找就消除了这个 bug

第十四次作业:

1、架构构思:

  本次作业是在上次作业的基础上进行扩展,UmlGeneralInteraction 接口继承了四个接口,分别是 UmlClassModelInteraction, UmlStandardPreCheck, UmlCollaborationInteraction, UmlStateChartInteraction。我将它们分别继承,实现各种的功能后再进行整合,其中:
  UmlClassModelInteraction 放入 classmodel包中,该包即上次作业的结构。
  UmlStandardPreCheck也放入 classmodel,并为它设置相应的 function,即 UmlRule
  UmlCollaborationInteractionUmlStateChartInteraction 分别放入新包 collaborationstatechart 中,并与上次作业相同,将方法归到各种的结构中,直接调用相应结构的方法。

2、项目分析:

类图分析:

度量分析:

3、自我总结:

  这次作业中的飘红主要是 UmlRule.checkClassUmlRule.checkCycle

 1 for (int i = 0; i < super.getLength(); i++) {
 2         for (int j = 0; j < super.getLength(); j++) {
 3             if (i == j) {
 4                 renewGraph[i][j] = 0;
 5         } else if (graph[i][j] == 0) {
 6                 renewGraph[i][j] = inf;
 7         } else {
 8                 renewGraph[i][j] = 1;
 9         }
10     }
11 }        

然而实际上只需要修改一下 bfs() ,在需要的时候判断一下,就能省去这个 O(n2) 的方法。当时可能是脑子轴了,没有想到。

4、程序bug分析:

这次作业我的强测爆的极其惨烈,原因在意“小心重构”的“小心”二字我没有做到。

bug 出现在 MyPathContainer.removePath()MyPathContainer.removePathById()。

为了将图的更新均摊到每一次 remove 操作,最初我是这样写的:

 1 if (distinctNode.get(pathId) == 1) {
 2     distinctNode.remove(pathId);
 3     removeList.add(removeId);
 4     mapping.remove(pathId);
 5 
 6     for (int i = 0; i < length; i++) {
 7         if (graph[removeId][i] != 0) {
 8             graph[removeId][i] = 0;
 9             graph[i][removeId] = 0;
10         }
11     }
12 } else {
13     distinctNode.put(pathId, distinctNode.get(pathId) - 1);
14         if (graph[removeId][prevId] != 0 && removeId != prevId) {
15             graph[removeId][prevId] = 0;
16             graph[prevId][removeId] = 0;
17     }
18 }

  每一次删除操作,我都将这个 Path 中的节点的所有边全部删除,如此错误的写法我当时居然没发现,实属不应该。

  因为这个头昏的写法,我的强测炸的妈都找不着了。

5、性能分析:

  性能方面,MyGraph 继承了上一次作业的 MyPathContainer ,相关方法的复杂度得到有效控制。

  而本次作业相关的图操作,除了我上文提到的 cache() 的简化问题,bfs 最多跑 20×n 次,每次复杂度O(V + E),所以复杂度完全可以接受。

四、架构设计及OO方法理解的演进

五、四个单元中测试理解与实践的演进

六、课程收获

七、给课程提三个具体改进建议

猜你喜欢

转载自www.cnblogs.com/tuoniao/p/11072828.html