BUAAOO Unit4:UML总结

BUAAOO Unit4:UML

1. 本单元的架构设计

1.1 第1次作业

UML层次图

  • UMLInteraction
    • UMLClass
      • UMLAttribute
      • UMLOperation
        • UMLParameter
      • UMLAssociation
        • UMLAssociationEnd
    • UMLInterface
    • UMLGeneralization
    • UMLInterfaceRealization

具体实现

初始化

在读入类图的各个元素后,要把类图的相应元素“匹配”到相应的层次,就如上面的UML层次图一样。除了上面的一些属性,需要注意的是每个Class有他继承的父类(如果有的话),每个Interface也有他继承的接口。所以我们可以根据上面这个层次图把每个class和Interface的性质都“设置”好。比如:把InterfaceRealization对应到class和interface的实现的接口parent;把Generalization对应到class和interface的parent

函数功能

本次作业要求实现的函数功能都比较简单,对于属性attribute的查询基本上都是要考虑继承关系,这时可以在Generalization初始化时,在每个class中,根据其继承关系(单继承)设置一个parent(UMLClass),方便沿着继承关系向上找各个父类。

UML图

image

可能出现的bug

要读懂题意,判断查询操作是否应该考虑继承关系

1.2 第2次作业&第3次作业

UML层次图

  • UMLClassModelInteraction
    • 同上次作业的Interaction下的架构
  • UMLCollaboration
    • UMLInteraction
      • UMLMessage

      • UMLLifeline

    • UMLAttribute
  • UMLStateChartInteraction
    • UMLRegion

      • UMLPseudostate(InitialState)

      • UMLFinalState

      • UMLState

      • UMLTransition

        • UMLEvent

        • UMLOpaqueBehavior

第3次作业添加的合法性检查并不影响第2次作业中的查询算法的实现。

具体实现

UMLCollaboration
  • 关于Attribute
    • 因为类图里面也有Attribute,所以需要区分attribute是属于类图还是属于顺序图的。我的处理是先初始化类图,在初始化类图的时候,需要把attribute对应到相应的class和interface里面,所以没有对应上的attribute就是属于顺序图的,把这些attribute放到一个list里,再传给顺序图
  • 在对IncomingMessageCountsentMessageCount
    • 我在将每个message对应到interaction的时候就设置了两个表
    • 一个是用HashMap<String, Interger> name2inMesCount来记录incomingMessage,前面的String是Message的target name,后面的Integer是message的数量。
    • 一个是用HashMap<String, HashMap<MessageSort, Integer>> name2sentMes,第一个String是message的source name,后面的Integer是每个MessageSort类型对应的message数。
    • 注意到这两个都是关于name和他们别的属性的对应,所以有可能有重名的lifelineName,这个时候先检查下这个name的lifeline是否唯一,如果不唯一就抛出异常即可。
UMLStateChartInteraction
  • subsequentCount
    • 记录一个状态可以到达的所有状态数(包括直接到达和间接到达)
    • 我的处理是对于一个状态,先把他能到达的所有直达顶点放到一个queue和map中,然后当queue不为空时,弹出一个元素,把它的所有直达顶点放到queue和map中(需要保证和原来在queue和map中的元素不重复),如此循环,直到queue为空,此时map的size就是所要求的的状态数。
  • findTransitionTrigger
    • 找到一个状态A到状态B的所有触发事件
    • 我的处理是在将Transition对应到Interaction时,先用一个tranId2Id来记录id1到id2的所有Transition(一个ArrayList),然后在查询时把这个ArrayList<Transitition>遍历,把每个event放到一个List里,最后返回。
StandardPreCheck
  • R002\R003\R004:采用BFS算法,没有进行优化(也没有T掉,万幸)
  • R005、R007:我都是设置了一个变量,在初始化的时候就检查,比如说R005:我设置了一个boolean isNullValid,在初始化的时候,遇到UMLClass、Interface、operation、direction不为return的parameter、还有类图中的attribute,当name为null时,将这个isNullValid置为true,然后返回,避免了查找时再对这些元素访问

UML图

image

可能出现的bug

在初始化的过程中,有可能会访问空指针,需要注意。

2. 四个单元的架构设计以及OO方法理解的演变

2.1 Unit1:多项式求导

多项式求导属于“开屏暴击”,由于我本身对Java就很不熟悉,再加上假期没有做pre,导致前三周我的作业都完成的十分匆忙,而且基本上都是在用面向过程的思想在实现,导致每一次的“迭代开发”都变成了重构,达成“三次作业,两次重构”的成就,直到第三次作业才开始慢慢地摸到门道。

第一次作业面向过程的影子很明显,在ExpressionTerm中都有很长篇幅的解析字符串的代码块,使得整个代码非常臃肿。而且我的代码只是面向第一次作业编程,并没有使用任何的继承,字符串的预处理和解析都在一个模块完成,并没有根据方法的功能严格划分各个方法,每个类的功能很复杂,并没有实现单个方法单个任务,类“形同虚设”,预示着我下次作业的重构。

第二次作业中没有使用递归下降法来解析表达式,而是使用表达式树,对下一次作业的风格检查和sin、cos里面套表达式无法适用,没有很好的扩展性。

经过这两次重构,我决心从下一次作业开始,好好设计架构,避免重构。

2.2 Unit2:电梯

这一单元吸取了上一单元重构的教训,我从在每次作业前都会提前打好草稿,想清楚自己要设计哪些类,每个类的功能都各自是什么,减少类与类之间的耦合,每个类实现的功能要单一。比如说主线程和读入线程分开,读入线程只负责读入和把请求放到缓冲区,主线程负责对类实例化和启动各个线程我将电梯的自身运行(例如开关门、到达、进出乘客)这些事都扔给了Elevator线程自己去做,即Elevator只管电梯的运行输出和进出人。把决定线程是否开关门、是否进出乘客、改变运行方向等这些事都丢给了Scheduler去做,即Scheduler管电梯自身的调度算法。

2.3 Unit3:JML

这一单元相对前面两单元难度是跳崖式变化,函数的功能可以根据JML规格来判断,这一单元的第一次作业主要是读懂JML规格的含义,了解JML规格的写法和一些语法,到后面两次更偏重于优化算法、选择什么样的容器和算法能让用时最少。

2.4 Unit4:UML

我仿照课程组给的jar包的架构,把自己实现的类分成了Element和Interaction两部分,这一单元的第一次作业我觉得还挺难的,毕竟从0到1总比从1到2难,看了很多UML的东西但感觉都跟课程联系不大,后来我思考了一下,主要是我们的解析各个UML模块,主要是要建立UML的树层结构(第一部分里列出的),在每个自己实现的类中建立好所属关系,比如说每个UMLClass有很多个Attribute,有很多个Operation,每个Operation里面有很多个Parameter这样。第二次作业添加的Collaboration和StateChartInteraction也是如法炮制,对于合法性检查,也是独立于这些函数的功能之外的,只需在原有基础上在初始化时顺便检查或者后面遍历检查。

3. 四个单元中测试理解与实践的演进

  1. 形式化验证

    在JML单元显得比较有效,对照JML规格进行形式化验证。我是先根据JML规格把规格“翻译”成自然语言,然后检查自己实现的代码是不是这样。因为有的时候写着写着就可能“多干一步”、或者“少干一步”,出现难以发现的bug,所以我认为对照JML进行验证算是不错的查找bug方法。

  2. 单个函数单独测试功能

    1. 因为我不太会写自动评测机,所以就只能手动构造数据了,基本上把能想到的一些情况都测了,但还有一个注意的地方就是,我有的时候是直接跑而不是debug模式,所以有些时候虽然结果是正确的,但可能多删了一些东西、或者少删了一些东西,在后面测试的时候才发现这个问题。
  3. 集成测试

    1. 这一部分主要与前面的测试相对,除了单独测试每个函数的功能外,还要生成覆盖面较广,对整体功能进行测试的用例。测试用例既要有普遍的,也要有专门针对优化算法设计的,数量要足够多。
  4. Junit测试

    1. 对于JML单元和UML单元来说,是一种比较好的测试方案

4. 课程收获

OO课程真的挺痛苦的,但收获也是很多的。比如说掌握了一门语言JAVA,了解了多线程、JML规格的写法和表示,UML元素以及UML图,了解了递归下降法等,最重要的就是面向对象的设计思想,面向过程和面向对象都有各自的好处,在一开始(好像现在也是这样)我对“类”的理解是C语言的结构体plus,除了定义各个变量还能写函数。但其实,如果要我说出“面向对象”的具体思想的话,我也说不出什么比较官方的话,我个人的理解就是把一个功能的实现下发给不同的“个体”,每个“个体”有自己的”属性“,可以有自己的“处理方法”(函数),相当于平日生活中的“责任到人”。这一学期的OO课,虽然累但是真的收获了很多,一开始接触这门课的时候感觉真的要难死了,第一单元都不知道从何下手,但随着每次作业的下发、构思、和同学间的探讨,我也慢慢地摸到了门路,能够从容应对每次作业,OO课程完结撒花。

5. 改进建议

  • 作业

    • 在每一单元的第一次作业后面可以写一下第二次作业和第三次作业主要都扩展什么内容,这样能够方便更好地想好架构(比如说第一单元如果知道后面要格式检查的话,可能在第一次就会开始上手递归下降,虽然说递归下降法不是作业的必须采用的方法)
  • 上机

    • 每次上机都不知道自己的成绩到底怎么样,如果可以在实验后公布上机成绩就好了。
    • 如果上机的代码阅读量比较大,或许可以提前半小时或者一小时开放代码库,让大家先阅读下代码,理解一下每个类实现的功能,比如说有一次实验是关于Java的垃圾回收机制,那次代码真的是又多又难,实验课时间又短,想要短时间内读懂代码又补全一部分功能的代码的话实在是有点困难
posted @ 2021-06-23 10:42  哆哆啦  阅读(86)  评论(0编辑  收藏  举报