- UML单元架构设计
- HW1
- HW2
- HW3
- 四个单元中架构设计及OO方法理解的演进
- Pre
- 第一单元
- 第二单元
- 第三单元
- 第四单元
- 四个单元中测试理解与实践的演进
- 第一单元
- 第二单元
- 第三单元
- 第四单元
- 三个具体改进建议
- 线上学习oo课程的体会
- 课程收获
UML单元架构设计
HW1
本次作业最终需要实现一个UML类图分析器,可以通过输入各种指令来进行类图有关信息的查询。
数据的存储通过MyUmlOperation
、MyUmlInterface
和MyUmlClass
三个类实现。MyUmlClassGraph
类通过解析后的输入建立相应的UML图,响应各种对图的查询要求。
官方包解析mdj
格式的文件为elements
数组,将各个UML类图元素传入MyUmlInteraction
类,以备后续处理。
MyUmlInteraction
类读入elements
数组创建了MyUmlCLassGraph
类型的graph
,由于elements
数组中的元素不是有序的,所以进行了多次读入,并使用HashMap
存储。
首先读入所有
elements
方便后续提取元素。读入类图的“节点”元素,包括UML_CLASS和UML_INTERFACE类型,创建相应的
MyUmlInterface
和MyUmlClass
对象,并存储到相应的HashMap
中统一管理。读入类图“节点”的“属性”元素,包括UML_ATTRIBUTE和UML_OPERATION类型,存储到相应节点对象中。
读入类图“节点”的“连边”元素,包括UML_GENERALIZATION、UML_INTERFACE_REALIZATION和UML_ASSOCIATION类型,存储到相应对象中。另外,读入UML_PARAMETER类型的元素,存储到相应OPERATION中。
MyUmlClass
类存储了类的父类、属性、操作、实现、关联。还存储了类的所有关联(考虑父类的继承)、顶级父类、类实现的全部接口(直接实现或通过父类或者接口继承等方式间接实现)方便二次重复查询。在相应的查询中大多采用递归的方式,递归的出口之一即为当前节点的相应属性已有数据。
MyUmlInterface
类存储了接口的操作、关联,用于协助类实现的所有接口的查询。由于查询操作中不设计接口的属性等,因此简化了其他不必要的数据存储。
MyUmlOperation
存储了操作的可见性和操作的参数。
HW2
本次作业,在上次作业基础上,扩展解析器,使得能够支持对UML顺序图和UML状态图的解析。
类图同HW1,平行增加了顺序图和状态图的相应处理。增加了这两种图的数据处理类MyUmlStateMachine
、MyUmlState
和MyUmlInteraction
、MyUmlLifeline
。也增加了MyUmlStateMachineGraph
、MyUmlCollaborationGraph
类通过解析后的输入建立相应的UML图,响应各种对图的查询要求。
同HW1,官方包解析mdj
格式的文件为elements
数组,将各个UML图元素传入MyUmlGeneralInteraction
类,以备后续处理。
MyUmlInteraction
类读入elements
数组分别创建了MyUmlCLassGraph
、MyUmlStateMachineGraph
、MyUmlCollaborationGraph
类型的graph
,由于elements
数组中的元素不是有序的,所以进行了多次读入,并使用HashMap
存储。
对于“给定状态机模型和其中的一个状态,有多少个不同的后继状态”的查询使用bfs直接查询所有可达的后继状态。
HW3
本次作业,在上次作业基础上,扩展解析器,使得能够支持对UML顺序图和UML状态图的解析,并对模型进行有效性检查。
对图的查询同HW1,增加了要求的八个有效性检查,这些检查调用相应的类型图对象的操作进行处理。
R001:针对下面给定的模型元素容器,不能含有重名的成员(UML002)
在MyUmlCLassGraph
类中增加关联对端所连接的UMLAssociationEnd,查询时在成员属性(UMLAttribute)和联对端所连接的UMLAssociationEnd 的集合中判重。
R002:不能有循环继承(UML008)
判断是否成环,对每个点进行dfs判断是否会回到此点。
R003:任何一个类或接口不能重复继承另外一个类或接口(UML007)
由于是顺序进行有效性检查,在检查完上一条规则后,使用bfs判断是否访问过已访问的节点即可。
R004:任何一个类不能重复实现同一个接口(UML009)
使用之前实现过的“查询类所有的实现接口”操作,将操作使用的去重HashSet修改为List,对List判重即可。
剩下的四个规则相比比较简单。
四个单元中架构设计及OO方法理解的演进
Pre
本单元作为课程准备,学习了java的基础语法,例如:表达式、for循环、if语句、输入输出、类、编译运行java程序等;学习了类和对象、构建构造方法和对类进行封装并理解封装的作用、类的继承关系、多态,设计模式中的工厂模式、正则表达式和容器。
第一单元
第一单元作业需要完成的任务为函数多项式求导,三次作业逐步引入不同的项和组合规则函数。复杂函数具有嵌套的树结构,对于函数和组合规则(常数、幂函数、三角函数、乘法、加减法)建立类对于上述的类均实现一个接口,包含求导方法getDeriv
和化简方法simplify
。把整个表达式构建为树结构,进行链式求导并优化。
在这一单元中学习了使用类来管理数据。初步建立了面向对象程序的认识,认识了对象的关键特性(可变性、相似性、可见性),理解层次化设计
按照数据/行为建立抽象层次
对多层次对象进行归一化管理进行了如何通过继承进行归一化的训练
面向对象是一种思维方法,包含三个重要的问题
如何管理对象
如何建立对象之间的层次关系
如何管理和利用层次关系
第二单元
第二单元作业需要完成的任务为多线程可捎带调度电梯的模拟,三次作业逐步引入并发成分和调度机制。主要采用了生产者消费者模式
Scheduler
类维护了共享的请求队列,以及volatile
类型的end flag
Input
类为生产者,读入Passenger
请求,加入请求队列
Elevator
类为消费者,取出Passenger
请求,加入电梯内部的Passenger
队列
在第三次作业中,由于存在中转乘客,Elevator
类既是生产者,又是消费者。中转乘客在第一程结束后出电梯,产生第二程新请求加入请求队列。
在这一单元中学习了多线程,包括识别线程及其共享数据,以及控制共享安全。在本次作业中了解到在面向对象方法中,对象不只是一个逻辑概念,也是运行时概念。
静态时的对象通过类定义其方法和属性,通过相应类型变量来引用和访问。第一单元关注静态的数据抽象和行为抽象,涉及的继承、接口、调用形成了面向问题分解和归纳的层次设计结构。
运行时对象存储在堆中,共享对象会进行全局性的访问管理。本单元关注动态的并发行为,涉及的线程、协同、同步形成了面向性能和资源控制的层次设计结构。
第三单元
第三单元作业需要实现一个社交关系模拟系统,逐步引入JML规格和复杂的中间数据模型。社交网络可抽象为一个图,采用HashMap
容器管理MyPerson
、MyGroup
和MyNetwork
,其中key
为id
,对图的查询操作基于bfs、dfs、堆优化的Dijkstra等,并设计了缓存操作。
在这一单元中学习了JML,根据功能需要适应性能要求的中间数据模型和协同架构。规格定义了与用户的契约和开发人员必须实现的规约,包括类规格和方法规格。
实现数据内容并确保始终有效
任意一个方法的实现都不能破坏对象的有效性
任意一个方法的实现都要满足方法本身定义的规约
前置条件:实现者可依赖的初始条件
后置条件:实现者如何提供满足要求的结果
副作用:不去做多余的事情
规格对程序的正确性进行了要求,但是如何在规格下进行架构设计是本单元训练的重点,比如要进行数据内容提取简化规格设计、用冗余存储换来性能提升等。在设计中需要考虑几个重要的问题
数据容器的选择
中间数据的存储和检索
规格的层次化
算法的选择
第四单元
第四单元作业需要实现一个UML图分析器,可以通过输入各种指令来进行图有关信息的查询,三次作业逐步引入了UML模型解析和语义规则。MyUmlInteraction
类读入elements
数组分别创建了MyUmlCLassGraph
、MyUmlStateMachineGraph
、MyUmlCollaborationGraph
类型的graph
,保存了相应的图数据结构,以响应各种查询。
在这一单元中针对诸多不同类型的对象构造层次和关系,在构造UML模型的过程中动态维护相关的查询数据。 UML模型是各种
四个单元中测试理解与实践的演进
第一单元
- 分类树
以设定的形式化表述出发,可能出现的情况表现为树形,简单构造各类情况的测试用例进行测试。
- 自动化测试
使用python package xeger、os、sympy进行随机测试用例生成、求导比较。
生成测试用例可根据正则表达式直接生成(hw1 n hw2)或分部生成(hw3),并控制各部生成概率
poly += xg.xeger("[+-]") + gen_term()
...
term += xg.xeger("\\*") + gen_factor()
...
第二单元
第一单元作业测试不关心求导过程的表达式状态变化,而第二单元多线程测试中关心电梯和队列的状态变化。设置断点的方法往往不能发现线程安全问题,所以主要采用System.err.println
通过输出信息进行debug
。对于一个bug
,通过批量随机测试+重复测试先判断此bug
为线程安全性bug
或非线程安全性bug
。非线程安全性bug
按照以往经验定位修改即可;由于线程安全问题的不可复现性,通过随机测试发现总结错误特点,将涉及共享资源部分逐步检查是否存在不安全问题。
- 基础性测试
构造所有可能出现的进出楼层电梯搭配进行基础性测试。
- 自动化测试
使用bash,python package subprocess、random、signal
进行随机测试用例生成、合法检查。
由于输入具有时间戳,生成测试用例并结合重定向运行代码
with subprocess.Popen([r'java', r'-jar', r'Elevators.jar'],
stdin=subprocess.PIPE,
text=True,
stdout=open(r'stdout.txt', "w"),
stderr=open(r'stderr.txt', "w")
) as subpcs:
covernRun(subpcs, 'test.txt')
第三单元
本单元的测试方法主要采用Junit
。在每一个测试方法中,首先需要构造测试用例,然后使用断言判断其是否能够得到预期的结果。
调用一个对象的repOK,检查一个对象的表示状态是否有效c.repOK()<==>invariant(c)
检查每个方法是否都满足规格,是否在任何使用场景下类都能确保状态正确
检查junit的覆盖率
第四单元
本单元的测试方法为手工测试,首先识别可能出现的所有场景,然后构造相应的图进行测试。
三个具体改进建议
实验课的设置目的不明确。如果是考试,应该严格要求纪律;如果是学习、为作业打基础等等(非考试),应设置相应的部分对实验进行讲解与答疑。
研讨课的内容价值不高。如果报名的人多研讨的讲解应该进一步筛选,报名的人少也可以提出一些主题同学直接进行讨论,没有必要凑数。
JML工具链博客作业的作用不大。我在完成这项作业的时候感觉就是在应付。
线上学习oo课程的体会
资料的回看和下载都很方便,完美解决了下午犯困的问题。
课程收获
- 深入了解并学习了面向对象的思维方法
- 学习了java语言、多线程、JML和UML
- 掌握了代码风格的要求
- 学会了自动化评测
- 学习了Markdown
- 巩固了图算法