OO_Unit4_UML

OO第四次博客作业

17231129 吴章杰

一、本单元作业的架构设计

第一次作业

本次作业最终需要实现一个UML类图解析器,可以通过输入各种指令来进行类图有关信息的查询。本次作业的程序主干逻辑均已实现,只需要完成对类图中各属性的查询操作。

首先,先分析类图的各个属性之间的关系:

(图片来源:https://course.buaaoo.top/assignment/80/discussion/245,感谢王珊珊同学的分享)

通过上面这张图,我们可以很清晰地看到各个标签之间的联系和层次结构。由此我们可以将类图依据层次关系划分成UmlClassUmlInterface两个类,其余的标签都作为属性附属于这两个大类。我们对UmlClassUmlInterface单独建模:

MyUmlClass

MyUmlInterface

分别根据他们的属性信息建立相应的数据结构以及传输信息的接口。

其次,具体分析每一条指令的查询内容,建立相应的查询方式。在查询信息时,可以运用缓存的思想,省去一些重复的搜索,但是可能会带来Flag横飞的后果。对于查询内容,还是应该加强对具体概念的理解,确保在查询时不会发生错误。(细心!)

最后,对输入信息进行分类,并根据各类信息的层次关系将各属性传入建立好的UmlClassUmlInterface两个类中。由于各类标签是有一定的层次关系的,所以应该先对信息进行分类,将信息整理与建立模型单独进行,确保在无序输入的情况下也适用。

第二次作业

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

本次作业是在前次作业的基础上进行一些功能扩展,基本架构与上次作业相似。

首先,本次作业需要对类图顺序图状态图三种不同的图进行解析,所以在上一次作业的基础上,对解析器分别建模UmlModelParserUmlStateMachineParserUmlCollaborationParser,以实现对模型的解析。

由于这三种图是相对独立的,且输入数据中可能不止有一种模型,所以在输入时这三个解析器应该是并列的

    public MyUmlGeneralInteraction(UmlElement... elements)
            throws UmlParseException {
        umlModelParser = new UmlModelParser(elements);
        umlStateMachineParser = new UmlStateMachineParser(elements);
        umlCollaborationParser = new UmlCollaborationParser(elements);
    }

同时有些属性可能不止在一种图中都出现,比如UmlAttribute可能同时出现在类图和顺序图中,若是顺序图的UmlAttribute就无法获得类图的parent。所以应该对解析器中所有get操作前进行判断是否是空指针,否则可能会喜提NullPointerException。

在建立好解析器之后,我们考虑各指令查询方式。

  • UML状态图
    • 状态数目(STATE_COUNT):即起始状态、UmlState和终止状态的总和。注意在本次作业中,若状态图中有多个起始状态(UmlPseudostate)或多个结束状态(UmlFinalState),都只计入一次。
    • 状态转移数目(TRANSITION_COUNT):即UmlTransition的个数
    • 某状态的后继状态数(SUBSEQUENT_STATE_COUNT):即某个状态之后所有可达状态的数目。(BFS搜索一下即可)
  • UML顺序图
    • 参与对象数目(PTCP_OBJ_COUNT):即UmlLifeline的个数
    • 交互消息数目(MESSAGE_COUNT):即UmlMessage的个数
    • incoming消息数目(INCOMING_MSG_COUNT):即某个UmlLifeline传入的信息个数。(遍历UmlMessage,统计target是该UmlLifeline的数目)
  • 模型有效性检查

模型有效性检查部分,将在实例化完毕后自动按序触发执行,不通过指令的形式。且一旦发现不符合规则的情况,将直接退出,不进行后续有效性检查和指令查询

    • R001:在原来的基础上对每个类进行遍历,检查类中所有的UMLAttribute及其关联对端所连接的UMLAssociationEnd是否有重名。
    • R002与R003:将所有的类和接口视为节点,以所有的继承关系(类与类、接口与接口、类与接口)实现关系(类与接口)为边,建立有向图。
    • R002等价于判断每个节点(即类/接口)是否存在自己到自己的通路(循环继承)。
    • R003等价于判断每个节点(即类/接口)以自己为起点的所有通路是否存在相同的节点(重复继承)。

二、架构设计与面向对象思想

万物皆对象

通过第一单元的学习,我开启了面向对象新世界的大门。从面向过程到面向对象无疑是思维方式和架构设计的一次巨大转变。

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;而面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

构造抽象层次,进行归一化处理。同时在保证正确性的前提下,对程序进行优化。

多线程

通过第二单元的学习,我掌握了多线程的基础知识和基本方法。多线程在给我们带来更高的资源利用率的同时,也给我们带来了程序设计复杂度的提升。线程之间的交互往往非常复杂。不正确的线程同步产生的错误非常难以被发现,并且重现以修复。这就需要我们更好地掌握多线程的运行机制来维护线程安全。

以程序的鲁棒性为主。在保证鲁棒性的前提下,追求性能的优化。

JML规格

通过第三单元的学习,我熟悉和掌握了JML的基本使用方法,了解了规格化概念在实际工程中的重要作用。JML帮助我们在进行程序设计时,使用更加规范的方式来描述每个类和方法的状态。通过基于规格的单元测试方法,我们可以进一步验证程序的正确性。

在本单元中,我学习和掌握了一些程序设计中的小trick,例如java容器的使用、图模型、中间数据缓存、复杂度优化等,拓宽了我的程序设计思维。

以JML规格为出发点,形式化验证程序的正确性,并结合算法和数据结构,对程序的复杂度进行优化;将性能与架构设计紧密结合,提升了程序的鲁棒性高效性

UML

通过第四单元的学习,我掌握了UML的基本知识,学会用类图描述程序的基本框架、用状态图和顺序图来描述程序运行时的状态和行为。在构造UML模型的过程中动态维护相关的查询数据,针对不同类型的对象构造层次关系。

UML使用系统化、模型化的语言来表示设计结果,为我们提供了一种更为直观明了的表现形式,便于我们开展架构设计思考。

三、测试与实践

在第一单元的多项式求导中,随机生成测试数据成了大多数人测试代码的手段。对拍器,懒人的标配——能拍中是福分,拍不中也是福分。但是往往拍中的bug都是同质bug,多交也不得分。这就需要自己构造一些特殊的测试样例,例如压力测试和非法输入测试。这些测试方法产出比高且容易得分,深受广大狼人喜爱。但是真正的狼人,是敢于直面代码。通过阅读代码,分析程序的逻辑结构,才可以挖掘出深层bug。

在第二单元的多线程中,测试变得极为困难,即使你通过某个样例找到一个bug,但由于多线程的不确定性,bug可能难以复现。可以利用JProfiler等软件分析CPU的运行情况,协助寻找bug。

在多线程程序中,bug极可能出现在线程等待和唤醒的地方。在定位bug时,可以在的wait/notify的前后输出相关信息,判断线程阻塞和唤醒的情况,同时还需要在程序中的某些循环语句中加入相应的标识,以便准确定位bug出现的地方。

在第三单元的JML规格设计中,我们通过编写单元测试类和方法,来实现对类和方法实现正确性的快速检查和测试。通过维护规格和测试代码的一致性,代码的可维护性得到了保障,程序的质量水平得到了提高。

四、课程收获

以上两点是我在学习课程知识上的收获。

但是OO带给我的不只有知识水平的丰富实践能力的锻炼,还有心理素质的提升

每一次重构,每一次爆零,

每一次被hack,每一次bug修复,

都是对我心理素质的磨炼。

曾经我以为,计组都熬过来了,还能有什么!直到我遇见了OO……

五、改进建议

  1. 建议课程组可以对实验课进行一些改进。既然实验课的定位不是“考试”,那么我觉得可以对实验课的题量和难度进行重新考量。同时,可以提前发布有关实验课的相关内容,以便同学能够有所准备。否则当天上午上完理论课,下午就上机实验有些令人难受。

  2. 建议课程组可以对理论课的课程内容进行适当的补充与精简。我个人感觉有时候OO课的内容太多了,以致于老师只能对着ppt泛泛而谈。一节课下来感觉什么都听了,却啥也没听懂。我觉得课上应该讲解课程的核心知识(可以多讲讲程序设计的架构,以及应用领域),而其它次要的内容可以作为补充材料供我们课下阅读。

  3. 建议在讨论区中对进行问题分类,并增加搜索功能

感谢OO课程组各位老师、助教一学期的辛勤付出!

谢谢你们!希望OO课能越来越好!

 

猜你喜欢

转载自www.cnblogs.com/jay-w/p/11074860.html