第四单元总结
第四单元总结性博客作业
1.总结本单元作业的架构设计
本单元作业主要是实现一个 UML 解析器,使其支持对 UML 图的分析,可以通过输入相应的指令来进行相关查询,同时还可以针对某些不符合UML规则的情况进行判断。
在本单元中,我采用的主体思路是:对于类图、顺序图、状态图这三种图用三个不同的类MyUmlClassModel, MyCollaboration, MyStateMachine
来分别表示,同时将处理每种图的逻辑装在每个子类中。在MyImplementation
类中,用HashMap
来储存所有的顺序图和状态图,同时由于每个UML图中最多只有一个类图,可以将类图作为MyImplementation
类的一个属性来储存。在对于类图查询时,就将问题交给类图给出答案;对于顺序图和状态图,首先通过HashMap
来找到对应的顺序图或者状态图,然后再由这个图给出问题的答案。
1.1 U4T1
第一次作业仅是对类图的查询。
对于类图,我采用了许多的HashMap
来保存各种信息
private final HashMap<UmlClass, UmlClass> umlClassMap; //考虑类单继承,类与它的父类可以装在一个Map表示
private final HashMap<UmlClass, ArrayList<UmlOperation>> operationMap; //类与类中对应的方法
private final HashMap<UmlInterface, ArrayList<UmlInterface>> interfaceMap; //接口与其继承的所有接口
private final HashMap<UmlClass, HashSet<UmlInterface>> realizationMap; //类与其实现的所有接口
private final HashMap<UmlOperation, ArrayList<UmlParameter>> parameterMap; //方法与其所有参数
private final HashMap<UmlClass, HashSet<UmlAttribute>> attributeMap; //类与类中的的所有属性
private final HashMap<UmlInterface, HashSet<UmlAttribute>> attributeInterfaceMap; //接口与接口中的所有属性
private final HashMap<UmlClass, Integer> couplingDegreeMap; //储存类的继承深度,便于查询
将所有信息条理清晰地储存起来,在进行后续查询/判断时也方便。
1.2 U4T2
第二次作业增加了对顺序图和状态图的查询。
顺序图:
private final ArrayList<UmlLifeline> lifelines; //顺序图中所有的lifeline
private final ArrayList<UmlEndpoint> endpoints; //顺序图中所有的endpoint
private final ArrayList<UmlMessage> messages; //顺序图中所有的Message
private final HashMap<UmlLifeline, HashSet<UmlLifeline>> creates; //判断一个lifeline能够创造的所有lifeline
private final HashMap<UmlLifeline, Integer> founds; //计数所有lifeline收到的found信息
private final HashMap<UmlLifeline, Integer> lost; //计数所有lifeline发出的lost信息
private final ArrayList<UmlAttribute> attributes; //顺序图中相关的属性
//UmlCollaboration作为每个顺序图的标志,在MyImplementation类的HashMap中储存
状态图:
private UmlPseudostate umlPseudostate; //起始状态
private final ArrayList<UmlState> umlStates; //所有状态
private final ArrayList<UmlFinalState> umlFinalStates; //所有最终状态
private final HashMap<UmlTransition, ArrayList<UmlEvent>> transitionAndEvents; //所有的迁移和迁移对应的事件
private final HashMap<UmlElement, Boolean> criticalJudge; //记录状态是否为关键状态
private final HashMap<UmlElement, ArrayList<UmlElement>> stateTree; //判断从一个状态能够到达的所有状态
private boolean flag; //判断原状态图是否能从起始状态到达任意一个最终状态
1.3 U4T3
第三次作业增加了对模型合法性的检查,包括R001~R009一共9个规则。
基本架构不用发生变化,只是在查询之前需要进行是否符合规则的判断。
2.总结自己在四个单元中架构设计思维及OO方法理解的演进
2.1 第一单元
首先是第一单元。第一单元我写的可谓一塌糊涂。。。第一单元的架构主要是参考了训练中的代码设计,将表达式分为Expr, Term, Factor三种类型,同时对于表达式进行递归下降处理。其实这个思路没什么问题,只是我实现的时候过于拘束在这三种类型的框架之中,所以我完全没有意识到我需要将Sin, Cos, Sum以及自定义表达式等等作为新的对象,建立新的类来处理(所以当时的架构写的很乱,计算过程自然也很乱)。在第三次作业的debug过程中,我才开始意识到明确对象、面向对象编程的重要性。
2.2 第二单元
然后就到了第二单元。第二单元主要是多线程,这单元的载体是电梯。此时的我架构反面仍然参考实验时候的代码,选择了输入线程、调度器线程、电梯线程多线程运行的结构。此时我选择的是将电梯作为对象,选择单例模式的调度器,各方面协调运转。此时的我对于架构设计虽然仍是在实验代码的基础上进行编写,但此时我已经逐渐理解了架构设计清晰对于程序设计的重要性,这个单元我也没有因为架构设计的问题而吃过亏(但是,在性能方面。。。)。在这时候,我逐渐加深了对于面向对编程的理解。
2.3 第三单元
之后就是第三单元,这时已经没有官方架构了,官方给出的是各个接口以及JML规格,我们只需要实现这些接口,剩余的架构设计就全部自由处理。第三单元我个人认为就是“你说什么,我就去实现什么”的感觉。在写第三单元作业的时候,我架构设计只需要保证我的逻辑清晰,要找什么数据我能够简洁明了的找到并且处理就可以。所以第三单元对于异常的计数我选择了单例模式的Counter来处理,各个异常都直接汇总到Counter,再有Counter给出计数就可以;对于MyPerson, MyGroup, MyNetwork
类,由于官方架构已经给出了数组的处理方式,所以只需要用ArrayList, Hashset, HashMap
等数据结构,逻辑清晰的储存即可。这一单元让我明确体会到了一个完备的JML规格能够对程序设计起到的关键作用。JML规格越完备,就可以越明确需求,在编程时就可以实现“说什么,就做什么”的一种“完全不用动脑子”的状态。
2.4 第四单元
最后就是第四单元。到了第四单元,也是没有官方架构,这回连JML规格都没有了。但是经过了前三单元的学习,我认为此时我的架构能够做到逻辑清晰有条理。架构方式正如第一部分所说。在这一单元的完成过程中,我已经开始切身体会到了架构有条理的好处——谁的事情,就交给谁去办。类图的事情类图给答案,顺序图的事情顺序图给答案,状态图的事情状态图给答案。这样代码编写时逻辑清晰,同时也提高了代码的可读性。同时,在这一单元中,我们对于Pre3 Task5中就提到的UML图进行了更加细致而深入的讲解,让我体会到一个完整的UML图对于程序设计初期的架构设计具有的强大的帮助作用。
3.总结自己在四个单元中测试理解与实践的演进
3.1 第一、二单元
前两个单元的测试主要是通过测试边界数据来进行测试。由于此时刚刚开始,所以手动操作的边界数据可能不够完善。
3.2 第三、四单元
第三单元开始介绍了JUnit的测试方式,此时的测试变得单元化、系统化,使得测试的准确性相对提高,找出bug的概率也提高了。
4.总结自己的课程收获
对于整个学期的面向对象课程的学习,我感觉到我受益匪浅。
4.1 程序编写要注重层次性、逻辑性
从第一单元的一塌糊涂,到第四个单元的游刃有余,我深刻的体会到程序编写过程中层次性、逻辑性的重要性。一份逻辑清晰有条理的代码对于编写者、读者,都是要比一份糊涂的代码要更容易理解。同时,在Debug的过程中,一份逻辑清晰的代码也更容易定位到bug的位置,提高效率。
4.2 程序编写初期要有明确的架构目标
一开始我写代码的时候喜欢直接上手开始写,一边写一边确定逻辑层次。但是,我现在发现这样做太容易走弯路了。由于有UML图的存在,在程序设计初期可以通过画一份UML图来思考、优化自己的代码架构设计,使得自己的代码在初期就有明确的架构目标,从而在实际上手时目的更加明确。
4.3 程序编写要有良好的可扩展性
本学期的代码课程分四个单元,每个单元都有三次作业,每次作业都是对于上一次作业的增量开发。这也就意味着,在写作业的同时,也要考虑到之后可能会添加的内容,要给程序留出足够的余地来进行扩展,也就是具有良好的可拓展性。如果对于一份代码,每次扩展都要大动筋骨,那么工作效率就会变得很低,这样完全不利于作业编写,更不用说工作展开了。
4.4 程序编写要确定每个方法(函数)的作用
事实上,第三单元的代码编写我感觉时非常舒服的——每个函数要干嘛都明确告诉了,需要做的就是实现这些目的。目前还是课内代码,代码量和实际工作中会遇到的代码量肯定时无法比较的。但是,对于每个函数,如果能够确定每个函数要做的事情,在JML规格中限定每个函数的作用范围,这样在编程时也能感到更加得心应手。
5.立足于自己的体会给课程提三个具体的改进建议
5.1 架构模式
可以对于架构模式多一些讲解。在刚开始看第二单元的代码时,我看的还是比较懵的,直到后来自己了解了一些内容后才逐渐理解。可以针对这方面多一些讲解。
5.2 单元之间的关系
感觉四个单元都在各讲各的,之间的联系不是非常密切(个人认为)。
5.3 测试相关
中测数据太弱!虽然我不知道这是否时课程组有意为之,但是一份有着明显bug的代码能够通过中测,就导致自己在课下进行测试时的压力提升。同时,互测时虽然是鼓励研究他人代码,寻找他人代码的bug,但是我个人感觉,一方面下载他人代码、配置jdk等等作为先决条件比较麻烦(第三单元还需要将他人代码和官方代码相结合),另一方面比起研究bug,直接采用高强度数据(甚至可以没那么高)进行hack的成功率也明显很高。这同样也暴露出中测数据的强度较弱。我不知道这些是否是课程组的故意安排,但我认为这样的设计对我而言相对不是非常合理的。