OO-Unit4&期末-总结
OO第四单元及期末总结
一、第四单元作业架构
本单元作业的主要任务是解析mdj格式的文件,需要做的工作是实现一个官方的接口,并完成其内部要求的方法。我们需要解析的有UML类图、UML状态图以及UML顺序图以及模型的有效性检查。
以下会具体介绍三次作业的设计架构。
第一次作业
第一次作业的UML类图以及相关信息如下:



第一次作业只需要我们解析UML类图,基本上只要按照方法描述填写方法内容即可。最关键的还是要理解mdj文件(json形式)的组成结果,谁是谁的parent,谁是谁的child。
至于设计架构中,个人使用了大量的hashmap来储存相关映射。由于每一个UmlElement都有唯一的id,因此其id可以作为map中的key与相关的value。
就像在UML类图中一样,个人设计架构的核心就是那些hashmap。以下解释其意义(解释一部分重要的变量):
| 属性名 | 作用 |
|---|---|
| allElement | 所有元素的id与元素实例的映射 |
| tree | 一元素id与其孩子节点id的映射,相当于多叉树 |
| classAttribute | 一个UmlClass元素的id与其所有属性的id的映射 |
| classNameNum | 一个class的名字对应有多少个相关class元素 |
| classNameToEle | class元素的名字与class元素的映射,当且仅当名字与元素一一对应时有效 |
| classParent | 一个class元素的id与其父类元素id的映射 |
| interfaceParent | 一个interface元素的id与其父接口id的映射,接口允许多继承 |
| associateClass | 一个class元素的id和与此class元素相关的的class元素的id的映射 |
| realizeInterface | 一个class元素的id和此class元素实现的接口的id的映射 |
以上是第一次作业中最重要的几个变量,个人是通过这些变量去实现所要求的方法的。而这些变量的实现有着诸多方法,只要在初始化时、调用覆写的接口方法前完成相关的建立操作即可。这些变量可以快速地完成相关方法,比如classNameNum可以快速判断给定的class name是否有效,有效后通过classNameToEle直接取出class元素,问top class时查询classParent不断向上溯源,求class实现接口时……
对于这些变量的实现,在遍历所有元素时,记录id与元素关系构成allElement,记录id与id的父子关系构成tree,同时分组保存好所有的class、interface、继承、实现、关联元素。遍历所有元素后先建立继承关系,即class与interface各自的父子关系树(hashmap),之后为每个class记录其属性,关联的class以及实现的接口即可。
第二次作业
第二次作业的UML类图以及相关信息如下:




第二次作业新增了UML状态图与UML顺序图的解析要求,与第一次作业的形式大致相似,关键还是谁是谁的parent、谁是谁的child问题。因此其结构与第一次作业大致相同,都是使用大量的HashMap去存储各种元素id的映射关系。
第二次作业的设计架构基本不变,但多了一个DealClass类去完成原本的解析UML类图的工作,本来还应该设置两个类去分别完成UML状态图与UML顺序图的任务,但因为这两个图的内容较少,因此没有实现。
其基本思路与第一次作业一致,使用大量的HashMap去管理数据。相比于第一次作业也新增了一些变量。以下展示的是一些较为重要的的变量,第一次作业有的便不予展示:
| 属性名 | 作用 |
|---|---|
| classOperation | class元素id与其内部的operation元素的id的映射, |
| machineNameNum | 状态机名字对应的状态机个数 |
| machineNameToEle | 状态机名字对应的状态机元素,当且仅当名字与元素一一对应时有效 |
| machineState | 状态机元素id与其内部state元素id的映射 |
| machineTransition | 状态机元素id与其内部transition元素id的映射 |
| afterState | state元素id与其后继state元素id的映射 |
| sequenceNameNum | 顺序图元素名字对应的顺序图个数 |
| sequenceNameToEle | 顺序图名字对应的顺序图元素,当且仅当名字与元素一一对应时有效 |
| sequenceObj | 顺序图元素id与其内部的对象(lifeLine)id的映射 |
| sequenceMessage | 顺序图元素id与其内部message元素id的映射 |
| messageIn | lifeLine元素id与传入此元素的message的id的映射 |
至于这些变量的使用与实现与第一次作业大致相同。
第三次作业
第三次作业的UML类图以及相关信息如下:





第三次作业在解析UML类图、UML状态图、UML顺序图的基础上,增加了8个模型有效性检查规则。在架构中,增加了DealState类、DealSequence类去分别处理状态图与顺序图的操作(这应该是第二次作业要完成的任务,为什么现在做?懒),增加了DealCheck类去专门处理有效性检查。
至于管理数据的变量,与第二次作业相比,并无重要增加。
三次作业总结
使用HashMap去管理各种数据会很方便,将各种任务分组后分配给其他类也可以让代码不会过于臃肿。
但这种方法也有一定的问题,大量HashMap占有内存(小问题),职责混乱,代码没有面向对象的思维。
可以对代码进行改进,既然一个class下需要记录其属性、方法等等要素,其实可以直接创建一个MyClass类去储存这些变量,对其进行整合、统一。对interface、状态机、顺序图同理。
二、 学期四单元架构设计 及 OO方法理解的演进
第一单元
第一单元是多项式求导化简及形式正误的判断。此单元作业的总体流程是解析输入、判断形式正误、求导与化简。主要是要求我们根据多项式的常数项、幂函数、因子、项等等去建立不同对象,利用多态特性去统一管理,构建不同的层次,利用求导接口使各个对象实现此接口完成求导,最后根据结果特性与特殊公式化简、合并同类项。
但是个人在当时并没有那么强的面向对象能力,因此代码基本是在面向过程。个人的处理模式也极为单一。首先使用正则表达式从因子到项到多项式,构建目标的正则表达式,之后使用正则表达式判断输入表达式格式是否正确;之后将表达式层层分割处理并储存;然后求导;最后化简。主要都还是面向过程的思维。
第二单元
第二单元是电梯调度,主要考察多线程的处理与应用。此单元作业的总体流程也就是利用官方接口处理输入,转换为要求,之后由电梯完成要求。
个人采用的设计架构使用的是生产者与消费者模型,生产者是输入处理类线程,生产要求交至缓冲区;消费者是电梯线程,从缓冲区中提取要求。个人采用的是电梯自调度算法,电梯会自动搜索缓冲区,取出合适自己的要求(是否合适根据电梯的可捎带算法决定)。第三次作业中,因为加入了换乘条件,所以个人在输入处理线程与电梯线程中加入了一个换乘调度线程,线程之间设有缓冲区,电梯同样采用自调度算法。
同时需要注意线程安全与暴力轮询的问题,线程安全问题可以使用锁解决,暴力轮询可使用wait,nitifyAll解决。但个人还是败倒在了轮询问题上,第三次作业出现了ctle的问题,出现了无效作业。
第三单元
第三单元是规格化设计,即根据JML规格填写代码。这个单元的关键还是在于对JML规格的理解,但写代码时不能完全照跟规格,需要灵活变通。
这个单元架构设计的关键有两点,一是数据的存储,二是缓存机制。对于数据的存储,要好好利用people与group的id的唯一性,根据这一点使用hashmap进行数据存储与映射,会大大减少程序运行时间,减少不必要的遍历;对于缓存机制,如果从开始我们就乖乖按照规格,每次询问时都老实计算,不借助缓存机制,那么我们的程序很可能会超时,出现ctle的情况。而使用缓存后也要注意缓存的更新,加入人、删除人、添加关系、删除关系时都会有不同的操作。
第四单元
第四单元是解析UML类图、UML状态图、UML顺序图以及模型有效性检查。具体架构设计见本文第一部分。
OO方法理解的演进
OO的十多次作业让我对面向对象方法有了很多不同的理解。
一开始,我对OO方法的理解还停留在java的class类中,它们实例化后会成为一个对象实例。但开始第一单元的作业后,我了解到了层次化的设计对代码结构的重要性,体会到了工厂模式的优劣所在,也成为面向过程到面向对象的过渡。到了第二单元,我感受到了,即使是在面向对象的核心类中,也同样需要确保线程安全,保证存储数据的完整性和有效性。同时自己也学到了生产者消费者模型,体会到了线程之间的协作。到了第三单元,面向对象还远远不够,我们还需要一种确定的规格、可以准确描述需求的语言,来帮助各个开发者之间的沟通与协作。同时还学会了如何使用Junit去测试代码的正确性。至于第四单元,知道了在OO代码中,各个部分、类、接口之间的的相互关系,学会了如何描绘类的状态变化与相互协作的方法。
总体而言,OO方法有着一个庞大的体系,有着不同的设计结构、成熟的模式方法等等,这些都需要我们日后去进一步学习。
三、测试理解与实践
首先是对于公测中的弱测,千万不要拿弱测去debug,弱测真的很弱。一定要自己多多测试,否则很容易翻船。
对于自己的测试方法。在学期开始时,我的测试手段还停留在人眼测试、手动构造边界样例和printf大法的级别。因此当时的测试水平还不高,经常出现拿弱测debug的行为。之后根据他人在讨论区的博客,以及自己上网查找资料,开始写代码、写自动测试程序(并不顺利)去测试自己的程序,但因为各种原因,这种方法还是很受限制。真正让我的测试方法有了质的飞跃的还是Junit。通过Junit,我可以使用自己构造的数据集对程序的各个部分进行单元测试,进行正确性判断。
四、课程收获
总体而言,本学期的OO课程还是让我收获颇丰。
首先是个人学习了java这门程序语言,理解的java的方便之处(和C相比),多掌握一些知识肯定还是有益的。
其次是学习了面向对象的思维,其中的层次化设计、线程安全问题、生产者消费者模式、工厂模式等令我印象深刻。
再次,自己学习到了JML规格语言,体会到了规格化的重要性。但是JML工具链真的很鸡肋
同时,自己还学到了如何构建自动测试程序的方法步骤,以及Junit测试的方法。
最后,是对自己学习习惯的影响。还是应该要多给自己设置一些ddl,去让自己多学一些知识、多做一些东西。OO的ddl就非常有效,它可以有效的逼迫我去学习。同时,这也暴露了自己的问题,自觉性还是不够高,需要督促自己把该完成的事情早点完成(不要拖到星期六下午[doge])。
最后的最后,OO课程训练了我临危不乱的能力,即使面临最后期限,即使是在周五晚上十点才开始写代码,我也可以谈笑自若(雾)。还给与了我舍生取义的勇气,OO实验8点56分左右提交代码。
五、三个建议
对于课程组,个人其实没想到什么改进建议,但既然问了,就好好挑挑骨头。
-
我认为第一单元的难度可能对刚刚接触OO的人来说太大了,那时才刚刚接触OO,个人还处于面向过程的状态,有些难以适应。不知道是否可以在pre中加入一些和第一单元更相关的内容,来一个过渡衔接。
-
对于OO研讨课,其实可讨论程度真的不高,发言人数真的不多。当然这可能和线上教学或是我们不积极的态度相关,但讨论内容的质量确实是参差不齐,有高有低。太高的让人听得云里雾里,太低的让人觉得是来水讨论分的,真的让我觉得有意义的讨论一学期也就那么几篇。研讨课对于研讨内容没有什么限制,这样确实可以鼓励大家去参加研讨课,但我认为还是要对内容进行一些限制的,应该把整体内容质量提高但也不至于太高,我认为这样会更有助于理解。
-
JML的工具链,配置困难、使用不便、效果也不咋滴。不知道是否能对这方面放低一些要求,或是给出一些教程(网上JML工具链的教程真不多,还大多是北航学长学姐的)。
六、 线上学习OO体会
我认为OO是一门比较特殊的课程,其课程形式是线上还是线下对课程的影响并像其他课程那样大。毕竟OO课程每一周都有具体的ddl来催促我们学习。
而且我认为即使是像以前一样在学校上课,和在家里也不会有太大的区别。每周作业或是博客在宿舍写和在家里写没什么区别。实验课在家里是用自己电脑,在学校好像也能用自己电脑(不确定,听说的)。
唯一的不同点可能就是在讨论上,很明显理论课与研讨课线上的讨论程度不高,虽然我也不知道线下会是什么情况,但应该不会比线上差吧(大概吧)。另外就是与舍友、同学之间的讨论少了,相互学习的机会也少了。
七、 其他
最后,十分感谢课程组的老师与助教。OO这门课程的体验确实很不错,有稳定的课程安排,每一周都有固定的模式、固定的ddl,同时也让我学会使用很多不同的工具。
总体而言,这门课程虽然有相当的难度,但同样也能带来相当的乐趣。

浙公网安备 33010602011771号