第四单元总结
第四单元总结
一、本单元架构分析
本单元的任务是完成一个UML图分析器。主要的框架并不需要我们完成,因此我觉得我们需要完成的就是在理解本单元作业各个元素之间关系的基础上,对这些元素进行结构化的管理,以便于在查询的时候可以尽量便捷地获得查询请求需要的信息。
本单元前两次作业的性质比较相似,分别是实现针对于UML类图的分析功能和针对于UML顺序图、UML状态图的分析功能。我选择的方法是对于每个实验中涉及到的元素种类都设置自己的类,并且根据请求指令涉及的属性,在这些类中设置自己的属性和方法。如下图所示:
在输入过程中,因为每一的元素的输入顺序不一定,因此我用五个循环来构造整个的树状结构,代码结构如下:
private void step1(UmlElement... elements) { for (UmlElement element : elements) { if (element instanceof UmlClass) { ...... } else if (element instanceof UmlInterface) { ...... } else if (element instanceof UmlCollaboration) { ...... } else if (element instanceof UmlStateMachine) { ...... } } } private void step2(UmlElement... elements) { for (UmlElement element : elements) { if (element instanceof UmlAssociationEnd) { ...... } else if (element instanceof UmlOperation) { ...... } else if (element instanceof UmlAttribute) { ...... } else if (element instanceof UmlGeneralization) { ...... } else if (element instanceof UmlInteraction) { ...... } else if (element instanceof UmlRegion) { ...... } } } private void step3(UmlElement... elements) { for (UmlElement element : elements) { if (element instanceof UmlAssociation) { ...... } else if (element instanceof UmlParameter) { ...... } else if (element instanceof UmlInterfaceRealization) { ...... } else if (element instanceof UmlEndpoint) { ...... } else if (element instanceof UmlLifeline) { ...... } else if ((element instanceof UmlPseudostate) || (element instanceof UmlFinalState) || (element instanceof UmlState) || (elementinstanceof UmlTransition)) { ...... } } } public void step4(UmlElement... elements) { for (UmlElement element : elements) { if (element instanceof UmlMessage) { ...... } else if (element instanceof UmlTransition) { ...... } } } public void step4(UmlElement... elements) { for (UmlElement element : elements) { if (element instanceof UmlEvent) { ...... } } }
同时,为了在之后的查询中能够直接获取到某些元素,运用HashMap容器按照一每个元素的id为key,以输入时新建的每一个元素对象为value,存入对应类型的容器中。虽然这样确实会造成空间的冗余,但是保证之后实现查询功能时可以省略掉一些循环。如下所示:
private HashMap<String,MyClass> classes = new HashMap<>(); private HashMap<String, MyInterface> interfaces = new HashMap<>(); private HashMap<String,MyAssociation> associations = new HashMap<>(); private HashMap<String,MyAttribute> attributes = new HashMap<>(); private HashMap<String,MyAssociationEnd> associationEnds = new HashMap<>(); private HashMap<String,MyParameter> parameters = new HashMap<>(); private HashMap<String,MyOperation> operations = new HashMap<>(); private HashMap<String,MyGeneralization> generalizations = new HashMap<>(); private HashMap<String,MyInterfaceRealization> interfaceRealizations = new HashMap<>(); private HashMap<String,MyCollaboration> collaborations = new HashMap<>(); private HashMap<String,MyInteraction> interactions = new HashMap<>(); private HashMap<String,MyEndpoint> endpoints = new HashMap<>(); private HashMap<String,MyLifeline> lifelines = new HashMap<>(); private HashMap<String,MyStateMachine> stateMachines = new HashMap<>(); private HashMap<String,MyRegion> regions = new HashMap<>(); private HashMap<String,MyTransition> transitions = new HashMap<>(); private HashMap<String,MyPseudostate> pseudostates = new HashMap<>(); private HashMap<String,MyState> states = new HashMap<>(); private HashMap<String,MyFinalState> finalStates = new HashMap<>(); private HashMap<String,MyMessage> messages = new HashMap<>();
第三次作业需要对输入的数据进行检查,依然是为了在处理指令时能够减少对容器中存储的对象进行遍历访问,我通过维护几个变量,在循环输入阶段就对是否存在第三次作业中需要检查的错误类型进行判断。像R001、R005、R006、R007还有R008这样只要存在就可以报错而不需要返回出现错误的元素的查询,就可以专门设置变量来简化处理。以R001为例,R001需要保证除了UmlAssociation、UmlAssociationEnd、UMLGeneralization和UmlInterfaceRealization以外的元素类型的name字段不为空。处理方法如下:
private int nameIsNull = 0; private void isNull(UmlElement element) { if (element.getName() == null) { nameIsNull = 1; } else if (element.getName().length() == 0 || element.getName().replaceAll("\\s","").length() == 0) { nameIsNull = 1; } } public void checkForUml001() throws UmlRule001Exception { if (nameIsNull == 1) { throw new UmlRule001Exception(); } }
二、四个单元中架构设计思维及OO方法理解的演进
第一单元
由于本身没有Java的基础而且对于新知识的领悟也比较缓慢,在寒假虽然预习过Java的语法知识,也做了预习内容,但是第一周拿到作业题面之后还是感觉无从下手。并且当时还没有养成实现设计架构的习惯,因此第一遍自己完成的时候存在很多漏洞,而且还是运用面向过程的思维方式、用一个老长的函数解决整个问题。第二次作业我选择了重构,参考训练代码向下递归的方法与讨论区的一些帖子,才终于有了一点面向对象的感觉。但是现在看来,第一单元我的三次作业其实在很大程度上保留了面向过程的思维方式。个人理解程度应该也是处于了解了大致方法,但是还不能熟练应用的阶段。
第二单元
本单元我尝试在动手写代码之前选对代码架构进行分析,并且在完成代码的时候真的比第一单元顺畅了许多,也很少再出现逻辑上的bug。但是这一单元感觉我的注意力更多是在多线程的实现上。还记得我在看到作业截止时间延期的通知时的激动,因为虽然听了理论课,也认真读了ppt,但是真正自己设计架构时还是有些摸不准多线程在某些情况下到底是怎么运行的。最后在理解实验课代码的基础上才完成的第二单元第一次作业的架构设计。除了对架构设计有了更加熟练地掌握,这一单元还了解了生产者消费者模型的应用以及不同线程访问临界区时的加锁方式,也在debug的过程中了解了线程不安全的具体体现形式与改正方法。
第三单元
第三单元需要按照JML规格来编写代码,整体的架构并不需要我们设计,感觉是OO课程中最友善的一个单元。在阅读JML规格的过程中,感觉自己理解较长JML规格的能力有所提升。完成代码时,感觉比较有难度的是降低时间复杂度,因为JML规格的实现方式并不唯一,即使使用了某些算法来降低时间复杂度,也可以通过选择更合适的容器或者维护一些变量的方式来进一步提升代码运行效率。因此除了需要准确理解JML规格的逻辑,同时还要注意细节的处理。
第四单元
本单元了解了UML图的结构,需要完成对UML图中的元素的存储与查询。感觉和第一单元的层次化设计比较类似,但是感觉对架构的设计已经有了比较清晰的思路。对我来说,这一单元的难点主要在理解与保存UML元素之间的关系上,由于本单元每种元素的属性与之间的关系比较琐碎,第一次作业的调试阶段感觉异常煎熬,因为实现时思考不够严谨,导致了很多bug。
三、四个单元中测试理解与实践的演进
第一单元的测试我采用手动构造一些样例来进行测试,但是效率较低,还是存在没考虑到的情况。
第二单元的测试我通过在可能出现问题的地方增加输出与查看CPU的方式来debug。优点是能够发现轮询的问题,缺点是没办法检测出电梯调度算法的效率是否够快。
第三单元的测试我使用Junits插件进行测试,虽然能较为全面地发现逻辑上的错误,但是比较繁琐,在检测算法的效率方面也十分受限。
第四单元的测试我通过构造UML图然后使用官方包导出数据的方式进行测试,缺点是覆盖到的情况较少,效率较低。
四、课程收获
养成了好的编程习惯。感受到了开始写代码前设计架构的重要性,动手前尽量完善的思考可以避免许多bug,甚至是重构。
形成了面向对象的思维模式,也掌握了Java这门语言。虽然从开学第一周就感受到了这门课程带来的压力,但是也能感受到自己迅速的变化,同时收获满满的成就感。
了解了关于多线程、JML规格、UML图、Dijkstra算法等的许多知识,并且在此基础上有一些实践。虽然是在学习面向对象的思维方式,但是也接触到了很多不同方面的知识,也感受到了OO这门课设计的用心。
更好的抗压能力与情绪调节能力。因为对自己解决问题能力的不自信,我比较容易焦虑,而焦虑的情况下又很难冷静下来思考问题。虽然刚开始因为OO课程这种不断提供新压力的规则设置委屈到哭,但是也确实让我能够在压力中尝试克服焦虑情绪、尝试解决问题,减少不必要的内耗。
五、立足于自己的体会给课程提三个具体的建议
在预习阶段加入关于多线程的练习内容。个人认为感觉第二单元最难的原因除了bug难de,还有多线程的设计思路的理解也比较费时间。如果事先对多线程有一些了解,可能会让第二单元的起步顺畅一些。
降低第一单元的难度,或是在预习中增加对第一单元内容的引导。感觉即使做了pre,看到第一次作业的题目还是不知道从哪里下手。