其他分享
首页 > 其他分享> > 「BUAA-OO」第四单元总结

「BUAA-OO」第四单元总结

作者:互联网

前言

在学习这一单元之前,我们仅仅是将UML当作一种"画图工具",仅仅知道它能帮助我们画出各种各样的类图、顺序图、状态图等等。但是,这样我们只是看到了UML的表象,却没有深刻理解其“统一建模语言”的本质。既然UML是一种语言,那它就应该既有"词汇",又有"语法"。通过理论课的学习我们已经知道,UML中的"词汇"就是一个个元模型(例如UMLClass、UMLRegion等等),而“语法”就是各个UML元模型之间的层次关系和组合关系。而本单元的三次作业,就是围绕着UML的"词汇"和"语法"进行展开,要求我们准确理解类图、顺序图和状态图中各个元模型和它们之间的关系,并在此基础上进行建模,实现一个功能较为完备的UML解析器。


作业架构分析

自建MyElement类

本单元的三次作业都是要求我们实现官方包UserApi接口中的方法,但是这并不意味着我们只需要写一个MyImplementation类就可以了(毕竟课程组怎么可能会这么温柔呢bushi)。尽管官方包已经将输入的json字符串解析并封装成了UMLClassUMLInterface等类,但是这些类中的信息仅仅是从json中迁移过来,对于完成作业来说还是远远不够的。

由此,我们可以自己新建MyClassMyInterface等类,里面不仅包含UMLClassUMLInterface等类的内容,还可以根据需要添加新的信息。例如,MyClass可以添加"继承的所有类的集合"、"实现的所有接口的集合","所有成员变量的集合","所有成员方法的集合", "继承深度"等等;MyRegion中可以添加"拥有的所有状态的集合";MyLifeline中可以添加"所有发出的lost message的集合","所有收到的found message的集合"等等。为了让自建类可以包含官方包已经封装好的类中的内容,我们可以通过"组合"的方式实现——

public class MyClass {
    private int depth;
    private UmlClass umlClass;

    private HashSet<String> fatherSet;          //继承的所有类
    private HashSet<String> sonSet;             //被继承的所有类
    private HashSet<String> interfaceSet;       //实现所有接口
    private HashSet<String> attributeSet;       //所有成员变量
    private HashSet<String> operationSet;       //所有成员方法
    private HashSet<String> associationEndSet;  //所有拥有的

    private ArrayList<String> allClasses;
    private HashSet<String> allInterfaces;
    private HashSet<String> allAttributes;

层次化建模

因为输入的json字符串的顺序无法得到保证,所以可能出现UMLGenerationUMLInterfaceRealization等元模型的出现时间要早于UMLClassUMLInterface和其他类似的情况,这给我们封装自建类带来的困难。一个比较好的解决办法是多次遍历elements,根据不同元模型之间的依赖关系来先后解析不同的UMLElement、并封装成MyElement

经过三次作业的迭代,我们最终可以通过5次遍历来解析所有的元模型——

这5次遍历可以直接在MyImplementation里进行。而为了防止因为行数过长而被StyleChecker制裁,我单独设置了一个Loop类来封装所有的遍历过程。·

public MyImplementation(UmlElement... elements) {
    Dict.getInstance().init();
    Loop.loop1(elements);
    Loop.loop2(elements);
    Loop.loop3(elements);
    Loop.loop4(elements);
    Loop.loop5(elements);
}

字典类

可以发现,MyClass中fatherSetsonSet等容器类存放的都是String类型的对象,很显然这些字符串都是表示元模型的id。因为每个元模型的id都是不同的,所以这样做既有操作上的便利性,也有实现上的可行性和安全性。但是——我们怎么通过id来找到对应的MyElement或者UMLElement呢?(有些UMLElement实际上不需要添加心得内容,因此不需要新建对应的MyElement)

为了解决这个问题,我新建了一个字典类——Dict,这个类中存放着所有的MyElement或者UMLElement。同时为了实现"根据id查找"和"根据name进行查找",我使用了HashMap作为容器来存放。

此外,Dict实际相当于全局的"recorder"和"seacher",为了保证在整个项目中只有一个实例,我还在Dict类中应用了单例模式。

public class Dict {
    private static final Dict DICT = new Dict();
    // Class Diagram
    private HashMap<String, MyClass> classMap;
    private HashMap<String, MyInterface> interfaceMap;
    private HashMap<String, MyOperation> operationMap;
    private HashMap<String, MyAttribute> attributeMap;
    private HashMap<String, MyParameter> parameterMap;
    private HashMap<String, MyAssociation> associationMap;
    private HashMap<String, UmlAssociationEnd> associationEndMap;
    // Sequence Diagram
    private HashMap<String, MyInteraction> interactionMap;
    private HashMap<String, MyLifeline> lifelineMap;
    private HashMap<String, UmlEndpoint> endpointMap;
    private HashMap<String, UmlMessage> messageMap;
    // State Diagrame
    private HashMap<String, MyStateMachine> stateMachineMap;
    private HashMap<String, MyRegion> regionMap;
    private HashMap<String, MyState> stateMap;
    private HashMap<String, MyPseudoState> pseudoStateMap;
    private HashMap<String, MyFinalState> finalStateMap;
    private HashMap<String, MyTransition> transitionMap;
    private HashMap<String, UmlEvent> triggerMap;
    private HashMap<String, UmlOpaqueBehavior> effectMap;
    // map for ’searching by name‘
    private HashMap<String, HashSet<MyClass>> classNameMap;
    private HashMap<String, HashSet<MyInteraction>> interactionNameMap;
    private HashMap<String, HashSet<MyStateMachine>> stateMachineNameMap;

    private Dict() {}

    public static Dict getInstance() {
        return DICT;
    }

    // functions for add
    public void addClass(UmlClass umlClass);
    public void addInterface(UmlInterface umlInterface);
    public void addLifeline(UmlLifeline umlLifeline);
    ...

    // functions for searching by id
    public MyClass getClassById(String id);
    public MyInterface getInterfaceById(String id);
    public MyLifeline getLifelineById(String id);
    ...

    // functions for searching by name
    public HashSet<MyClass> getClassByName(String name);
    public HashSet<MyInteraction> getInteractionByName(String name)
    public HashSet<MyStateMachine> getStateMachineByName(String name);
    ...

}

在进行elements的五次遍历时,我们可以将遍历到的 UMLElement 通过Dict类的add方法加入到对应的容器中。需要注意的是,对于那些需要扩展的 UMLElementDict会先调用自建类的构造方法将其转化成MyElement,然后再加入对应的容器。

架构设计思维和OO方法理解的演进

测试的理解和实践

在这四个单元中我都是采用了 "单元测试+随机测试+边缘数据测试" 的测试流程。

课程收获

改进建议

标签:OO,HashMap,BUAA,private,测试,UML,public,单元
来源: https://www.cnblogs.com/hyggge/p/16413290.html