BUAA-OO-final-chapter

BUAA-OO-final-chapter

第四单元架构设计

三次作业放在一起总结。

  • 作业是迭代开发的,最后全部类图如下所示。

image

  • 层次化:

    • 为了更好的组织信息,对UmlElement按照其原有的层次进行自定义封装,提升代码的可拓展性,降低耦合度、单个文件代码行数等。

    • 自定义元素组合关系如下:

      graph TD subgraph MyImplementation subgraph ClassDiagram subgraph MyClassOrInterface subgraph MyClass MyOperation end MyInterface end end subgraph SequenceDiagram subgraph MyInteraction MyLifeline end end subgraph StateDiagram subgraph MyStateMachine subgraph MyRegion MyState end end end end
  • 细节一:对传入的UmlElement建立层次关系时,需要按照层次进行多次遍历,以保证正确性不遗漏。parsing的顺序如下:

    • for (UmlElement e: elements) {
                  if (e instanceof UmlClass) {
                      classDiagram.parseUmlClass((UmlClass) e);
                  } else if (e instanceof UmlInterface) {
                      classDiagram.parseUmlInterface((UmlInterface) e);
                  }
              }
              for (UmlElement e: elements) {
                  if (e instanceof UmlAssociationEnd) {
                      classDiagram.parseUmlAssociationEnd((UmlAssociationEnd) e);
                  } else if (e instanceof UmlAttribute) {
                      classDiagram.parseUmlAttribute((UmlAttribute) e);
                      sequenceDiagram.parseUmlAttribute((UmlAttribute) e);
                  } else if (e instanceof UmlGeneralization) {
                      classDiagram.parseUmlGeneralization((UmlGeneralization) e);
                  } else if (e instanceof UmlInterfaceRealization) {
                      classDiagram.parseUmlInterfaceRealization((UmlInterfaceRealization) e);
                  } else if (e instanceof UmlOperation) {
                      classDiagram.parseUmlOperation((UmlOperation) e);
                  } else if (e instanceof UmlStateMachine) {
                      stateDiagram.parseUmlStateMachine((UmlStateMachine) e);
                  } else if (e instanceof UmlInteraction) {
                      sequenceDiagram.parseUmlInteraction((UmlInteraction) e);
                  }
              }
              for (UmlElement e : elements) {
                  if (e instanceof UmlAssociation) {
                      classDiagram.parseUmlAssociation((UmlAssociation) e);
                  } else if (e instanceof UmlParameter) {
                      classDiagram.parseUmlParameter((UmlParameter) e);
                  } else if (e instanceof UmlRegion) {
                      stateDiagram.parseUmlRegion((UmlRegion) e);
                  } else if (e instanceof UmlLifeline) {
                      sequenceDiagram.parseUmlLifeline((UmlLifeline) e);
                  }
              }
              for (UmlElement e : elements) {
                  if ((e instanceof UmlState) || (e instanceof UmlFinalState)
                          || (e instanceof UmlPseudostate)) {
                      stateDiagram.parseUmlGeneralState(e);
                  } else if (e instanceof UmlMessage) {
                      sequenceDiagram.parseUmlMessage((UmlMessage) e);
                  }
              }
              secondPart(elements);
      
          }
      
          private void secondPart(UmlElement[] elements) {
              for (UmlElement e : elements) {
                  if (e instanceof UmlTransition) {
                      stateDiagram.parseUmlTransaction((UmlTransition) e);
                  }
              }
              for (UmlElement e : elements) {
                  if (e instanceof UmlEvent) {
                      stateDiagram.parseUmlEvent((UmlEvent) e);
                  }
              }
          }
      
  • 由于数据规模较小,对于所有的查询、检查指令,都可以使用直接模拟、暴力搜索的方式解决,对算法要求较低。

四个单元的架构思维及OO思想的演进

按照STAR----situation-task-action-result的顺序对各个单元简要分析。

第一单元

  • 本单元的主要任务是完成表达式的建模与化简。
  • 架构上,最为关键的就是层次化设计:体现在,表达式结构的层次化、递归下降解析的层次化等。
    • 对表达式、项、因子进行层次化建模,借助表达式本身的结构去做数据抽象。
    • 工厂模式提升可拓展性,应用依赖倒转原则解耦。
  • 思想上,主要对封装、继承多态、数据抽象,以及面向对象的几个设计原则有了体会。认识到架构设计的重要性。

第二单元

flowchart LR i(personRequest)--break down-->a a(RequestPool)--get transferFloor-->b(floor1)--assign elevator-->c(elevator)-->a c-->c a(RequestPool)--get transferFloor-->bb(floor2)--assign elevator-->c2(elevator)-->a c2-->c2 a(RequestPool)--get transferFloor-->bbb(floor3)--assign elevator-->c3(elevator)-->a c3-->c3
  • 本单元的主要任务是多线程电梯的模拟。关键在于处理好各个线程间的协作同步,处理好调度与线程的交互问题。
  • 为此,架构上,设计了输入线程与电梯线程两类线程,并按需封装了共享资源类、人类、楼层类等。同时,选用三级调度机制:在拿到新请求后应拆分请求至相应的换乘楼层(第一级调度);在换乘楼层楼座需要安排所乘电梯(第二级调度);电梯本身的运行策略可看作第三级调度。这样一来,也较为简洁的实现了调度器与线程的交互。
  • 思想上,这一单元主要体现了设计模式的应用。我的作业就是基于生产者消费者模型设计的。经过这一单元的学习,对多线程模型,设计模式等内容都有了较深的体会。

第三单元

  • 第三单元主要任务就是实现相应规格,相应的,对契约式编程、异常处理、软件测试等方面也有一定要求。
  • 架构上,除了按照规格设计,还封装了维护图模型的类,单例的异常处理计数模块等。
  • 通过本单元,学习到了规格化设计、契约式编程的思想;也学习到了异常处理、单元测试相关的知识。

第四单元

  • 第四单元的主要任务是完成对UML类图、时序图、状态图的建模和检查、查询。可以看作是第一单元(建模),与第三单元(查询指令)的结合。
  • 架构上,如前面所述,主要是层次化进行建模,对UML模型中的元素进行数据抽象。总的来说,经过本单元的学习,也相当于对前面所学到的各种设计、测试、思想方法进行了总结。

关于测试

测试的策略

在OO课程与软件开发中,测试始终是一门重要的学问。回顾已经过去的四个单元,可以总结出以下几种测试策略:

  • 第一单元的测试:主要采用随机生成数据,借助python符号计算包sympy化简表达式进行答案比对的方法,实现较高的测试覆盖率。
graph LR subgraph test in U1 C(Generator)--generate data-->B(Tester)--get result-->A C--data-->G(sympy)--res-->A A(Judgee) end
  • 第二单元的测试:由于不同的答案可能都是正确的,因此无法采用对拍的策略,只能按照电梯的运行规则编写数据检查器,来检验电梯行为的正确性。同样可以利用大量的随机数据得到答案,再通过数据检查器即可。
graph LR subgraph test in U2 C(Generator)--generate data-->B(Tester)--get result-->A A(Checker: a FSM) A--shift state-->A end
  • 第三/四单元的测试:这两单元的作业有如下几个性质:1)得到的答案唯一,可以利用对拍检查;2)给出了方法的规格/指令的行为,能够较好的量化方法的行为,从而实现更细粒度的测试(单元测试),以提升程序的鲁棒性,降低debug的难度。

    基于上面的性质,我采用了多层的测试来验证程序的正确性。在类与方法的层面,使用JUNIT进行单元测试;在整个程序的宏观层面上,采用与小伙伴对拍的方式测试。先借助单元测试确定大体的正确性,再用随机数据对拍覆盖较为复杂的cornerCase。示意如下:

flowchart LR UnitTest--for more thorough test-->BeatMatching subgraph UnitTest O(Tester)--generate-->A A(testCase)--data-->B(class to be tested) B-->C(Actual Output) A--provide-->D(Correct Output) subgraph Assert! C-->E(compare) D-->E(compare) end E--true-->G(next TestCase) E--false-->F(Exception) end subgraph BeatMatching C1(Generator)--generate data-->B1(Victim1)--get result-->A1 C1(Generator)--generate data-->dd1(Victim2)--get result-->A1 C1(Generator)--generate data-->Bd1(Victim3)--get result-->A1 A1(Judger) A1--compare between each other-->A1 end
  • 特别的,第三单元中基于规格进行测试的流程如下:
    • 每个前置条件对应两个正例、负例
    • 每个后置条件用assert检查正确性

课程收获

总体收获

  • 在实践中深化oo思想:封装多态继承、层次化、数据抽象...只有在实践中应用,才能对这些概念有更深的理解。

    面向对象设计原则:李氏代换原则,依赖倒转原则,单一功能原则、开闭原则等。

  • 对软件测试有了更加深入的了解。对各种测试方式,如单元测试、回归测试、大量数据随机测试等,都在每一单元进行了实践。

  • Java语言:对java语言的使用,java多线程等功能,有了一定的掌握。同时也了解并实践了现代面向对象语言的一些特性,如:函数式接口、容器的使用、等等。

  • 设计模式:了解了很多设计模式,并对工厂模式、单例模式、抽象方法模式等进行了实践,了解了生产者模型、流水线模型等。

  • 代码规范:由于中学的算法竞赛经历,以前在代码风格上有一些不太好的习惯,如压行、不遵守规范等。直到oo这门课程,才改了过来,建立起较好的代码规范。

  • 各种辅助工具的了解,如git、checkstyle等。

各单元收获

  • 第一单元:层次化的设计思想,同时学习到了递归下降的知识。

  • 第二单元:在实践中学习了多线程的相关知识,包括但不限于:多线程与各种锁的原理,多线程设计模式和架构、锁的应用等;也学习了调度相关的一些知识。

  • 第三单元:对软件测试有了一定认识。学会使用规格,单元测试等。

  • 第四单元:学会了UML建模的相关细节知识。

课程建议

  • 首先是关于第二单元的互测的一点小看法:一方面,我很欣赏课程组为了降低互测压力所做的努力,也了解课程组所鼓励的互测方法:即阅读代码找出错误并设计样例、而不是一味的用大量随机数据爆破。不过,对互测数据过于严格的限制还是很大程度上消减了同学们对互测的兴致——如,很难针对超时的调度方法设计数据等——我觉得这一点或许能够在今后做到更好的权衡。
  • 其次关于实验,希望能在试验后,提供实验的评测结果,更好的供同学们学习。
  • 关于JML单元:
    • 在理论课中,或许可以对各种软件测试方法、JML自动化工具链做更多细节的讨论。
    • JML这一单元很大一部分是关于测试的。因此,在实验课或作业中,可以增加有关JUnit单元测试等测试相关内容。
  • 关于讨论区:可以增加删帖功能。
posted @ 2022-06-29 12:10  gnwekge  阅读(10)  评论(1编辑  收藏  举报