BUAA面向对象课程博客 第4弹: UML建模与课程总结
1 本单元作业的架构设计
本单元作业的需求是输入UML模型元素序列,完成对UML模型相关信息的查询。
1.1 第一次作业:类图
1.1.1 数据结构建立
-
零级模型:类图
构建顶层容器,保管类图所有元素。
-
一级模型:类、接口
添加至类图。 -
二级模型:属性、方法、关联端
添加至对应类或接口。 -
三级模型:参数
添加至对应方法。 -
关系模型:泛化、实现、关联
泛化:将对应子类/接口与父类、接口互相添加。
实现:将对应接口添加至实现其的类中。
关联:将关联的两端彼此添加。
1.1.2 查询指令实现
-
指令1 CLASS_COUNT
查询类图中类的总数,由类图顶层模型给出其中类的数目。 -
指令2 CLASS_SUBCLASS_COUNT classname
查询名为className的类的子类数量。直接由对应类给出。 -
指令3 CLASS_OPERATION_COUNT classname
查询名为className的类的方法数量,直接由对应类给出。 -
指令4 CLASS_OPERATION_VISIBILITY classname methodname
查询名为className的类的名为methedName方法的可见性分布。由对应类统计所有对应方法各种可见性出现的次数。 -
指令5 CLASS_OPERATION_COUPLING_DEGREE classname methodname
查询名为className的类的名为methedName方法的耦合度。由对应类统计其中的所有对应方法的引用型参数所引用的其它类或接口的个数。 -
指令6 CLASS_ATTR_COUPLING_DEGREE classname
查询名为className的类的属性耦合度,考虑继承。由对应类统计其自身属性引用的类或接口,递归调用父类的查询并合并,再出去自身。 -
指令7 CLASS_IMPLEMENT_INTERFACE_LIST classname
查询名为className的类实现的接口列表,考虑继承。由对应类查找其实现的接口:它本身实现的接口与递归查询其父类实现的接口。 -
指令8 CLASS_DEPTH_OF_INHERITANCE classname
查询名为className的类实现的继承深度。若无父类则为零,否则为其父类继承深度加一。
1.2 第二次作业I:顺序图
1.2.1 数据结构建立
-
零级模型:顺序图
构建顶层容器,保管顺序图所有元素。 -
一级模型:Collaboration
添加至顺序图。 -
二级模型:Interaction, Attribute
添加至对应Collaboration。 -
三级模型:Lifeline, Endpoint
添加至对应Interaction。 -
四级模型:Message
添加至对应Lifeline或Endpoint。
1.2.2 查询指令实现
-
指令1 PTCP_OBJ_COUNT umlinteraction_name
查询名为umlinteraction的interaction中lifeline的数目。直接由对应interaction给出。 -
指令2 PTCP_CREATOR umlinteraction_name lifeline_name
查询名为umlinteraction_name的Interaction中名为lifeline_name的Lifeline的创造者。由对应Lifeline给出其收到的CREATE型Message的来源。 -
指令3 PTCP_LOST_AND_FOUND umlinteraction_name lifeline_name
查询名为umlinteraction_name的Interaction中名为lifeline_name的Lifeline的LOST消息与FOUND消息数目。由对应Lifeline给出其与EndPoint收发消息的数目。
1.3 第二次作业II:状态图
1.3.1 数据结构建立
-
零级模型:状态图
构建顶层容器,保管状态图所有元素。 -
一级模型:StateMachine
添加至顺序图。 -
二级模型:Region
添加至对应StateMachine。 -
三级模型:Pseudostate, State, FinalState, Transtion
添加至对应Region。 -
四级模型:Event, OpaqueBehavior
添加至对应Transtion。
1.3.2 查询指令实现
-
指令1 STATE_COUNT statemachine_name
查询名为statemachine_name的状态机的状态个数。先由状态图顶层模型按名查找状态机,然后由状态机给出其初始状态、一般状态、最终状态的个数。 -
指令2 STATE_IS_CRITICAL_POINT statemachine_name statename
查询名为statemachine_name的状态机的名为statename的状态是否是关键状态。先由状态图顶层模型按名查找状态机,然后由状态机给出该状态是否为关键状态。算法:带禁止点的DFS。若该状态机在禁止通过此状态时,从初始状态开始DFS不可以到达任意一个最终状态;且在允许通过此状态时,从初始状态开始DFS可以到达至少一个最终状态,则该状态为关键状态。
-
指令3 TRANSITION_TRIGGER statemachine_name statename1 statename2
查询名为statemachine_name的状态机的名为statename1到名为statename2的状态的所有触发事件。先由状态图顶层模型按名查找状态机,然后由状态机按名查找两个状态及其之间所有转移,汇总所有转移的事件。
1.3 第三次作业:合法性检验
-
**R001: 类图元素名字不能为空(UML 001)
依次检查类图中所有类、接口、属性、方法、非返回的参数的名称为非空即可。 -
R002:类的属性与关联另一端不能含有重名的成员(UML 002)
由所有类检查其所有属性与所有关联另一端的名字是否有重复。 -
R003:不能有循环继承(UML008)
类图使用tarjan算法找出类与接口继承网络中所有强连通分量。所有连通分量的节点,均存在循环继承。
tarjan算法:- tarjan算法是基于DFS的强连通分量划分算法,可以在一次DFS中超出有向图所有强连通分量。定义DFN[i]:节点i在DFS被访问的次序;定义LOW[i]:由节点i可达的节点j中DFN[j]的最小值。
- 遍历图中每一个节点,若未访问过,则使用DFS访问;
- 访问每个节点i时:
- 将其入访问栈;
- 初始化LOW[i] = DFN[i] = 其被访问的次序;
- 遍历其邻接节点j:
- 若未访问过,则访问它,并更新LOW[i] = MIN{LOW[i], LOW[j]};
- 若访问过且j在栈中,则更新LOW[i] = MIN{LOW[i], DFN[j]};
- 若LOW[i] = DFN[i],则将访问栈中节点i及其之上的节点全部出栈,此为一个强连通分量;
-
R004:任何一个类或接口不能重复继承另外一个类或接口(UML007)
类图使用DFS算法检验每个类与接口是否有重复继承。若以该类或接口开始,沿继承网络DFS搜索到同一类或接口两次,则存在。 -
R005: 接口的所有属性均需要为 public(UML 011)
由所有Interface检查其属性的Visibility均为PUBLIC。 -
R006:Lifeline 必须表示在同一 Sequence Diagram 中定义的 Attribute
由所有Collaboration检查其中的Lifeline的Represent均是同Collaboration下的Attribute。 -
R007:一个 Lifeline 在被销毁后不能再收到任何消息
由所有Lifeline检查其收到的Message的序列,是否在DELETE类型的Message后还有其它Message。 -
R008:所有 FinalState 状态不能有任何迁出(UML 033)
由所有Region检查其中所有Trasition的起点均不是FinalState。 -
R009:一个状态不能有两个条件相同的迁出
由所有Region检查其中所有的State迁出的Trasition的集合,不能有两个相同Gaurd的Trasition包含同名的Event。
2 架构设计思维及OO方法理解的演进
2.1 第一单元
-
行为抽象:表达式化简很复杂,但算数式计算却很简单。对比这两者之间的差别,发现不同之处在于加减乘除运算。因此,只要抽象出表达式的运算方法,表达式化简就如算数式计算一样简单。
-
层次化设计:进一步简化算数式计算的算法。无需自行管理计算栈,而是通过加减、乘法、括号子式的分层处理,使得上层使用下层封装的抽象接口,用递归调用代替栈。
本单元的收获在于初步建立了对面向对象抽象的理解。
2.2 第二单元
-
设计模式:多线程编程的安全性保证十分复杂,但是如果使用一些前人总结的设计模式就变得简单了。
-
开闭原则:我们加入新功能,要考虑加入新的模块,而非总是修改已有的代码。结合设计模式,则开发迭代可以转变为一系列已有设计模式的加入,可以让我们的开发变得更加高效。
本单元的收获在于学会了如何使用设计模式使设计变得简单,以及如何通过增量开发来实现新的功能。
2.3 第三单元
-
设计分离:程序设计时不首先关心实现,而是先考虑每个类的功能:其需要维护的属性变量,其方法的输入输出规格。最终再考虑这些功能的实现。
-
泛型编程:将一些常用的算法实现使用泛型封装起来,待需要时直接调用接口。与设计分离结合,可以使开发高效可靠。
本单元的收获在于学会了如何使用规格化使开发更高效,合作更顺利。
2.4 第四单元
- 数据结构建立与操作实现分离:首先使用合适的数据结构保存输入的全部信息,然后再增量开发其上的各种操作,可以最大化程序可扩展性。
本单元的收获在于学会了UML代表的树状数据结构的管理与查询。
3 我对测试理解与实践的演进
3.1 第一单元
- 理解:测试的关键在于样例的复杂度,越复杂的数据可以检测的bug越多;
- 实践:努力手动构造各种复杂的数据;
3.2 第二单元
- 理解:测试的关键在于大量,许多简单数据可以覆盖一个复杂数据;
- 实践:设计自动样例生成与结果检验程序,自动化大量测试;
3.3 第三单元
- 理解:测试需要提高覆盖率,单元测试比黑箱测试更容易做到这一点;
- 实践:针对每个方法进行单独测试;
3.4 第四单元
- 理解:测试除了检验正确性,还能加速开发;
- 实践:在开发的同时进行测试,面向debug开发;
4 我的课程收获
-
学会了用面向对象写大规模代码
学会使用面向对象的技术,设计各种好用的类,实现整洁的大规模程序代码。 -
学会了自动化测试
使用java正则化表达式以及面向对象的技术设计数据生成器与结果检测器。 -
学会了用博客记录自己的想法
多次博客写作训练,让我熟练了博客写作。
5 我的改进建议
-
增加小组合作机制
面向对象开发与测试的课下任务较重,独立完成完整的开发与测试其实较为困难,设立小组合作有助于同学们交流设计思路与合作测试,进一步扩展学习的内容。同时,也能与互测中和,增强合作意识。据观察,面向对象取得优秀成绩的同学都乐于互相帮助。 -
增加实战体验
可以通过官方包提供如网页或swing用户界面接口,使学生实现部分后端功能,实现一个可以使用的软件。 -
理论课与研讨课联系实际
认真地思考顶层的抽象设计是十分重要的,但是仅仅思考这些是不够的。当前理论课与研讨课在这些内容的学习有些重复冗余,希望理论课与研讨课可以多花些时间联系code学习更多高级架构的具体实现。
posted on 2022-06-29 15:14 ^^^TOO_LOW^^^ 阅读(67) 评论(1) 编辑 收藏 举报