BUAA_OO_Unit4
BUAA_OO_Unit4
本单元需要实现一个UML解析器的核心功能。
一、架构设计
下面分次介绍设计细节:
1.1 第十三次作业——建立类图
增加类MyClassDiagram
,MyAssociation
,MyClass
,MyInterface
,MyNameableType
,MyOperation
.
-
数据的读入
使用多次遍历的方法读入数据,将具体加入过程封装在MyClassDiagram
对象中。
public MyImplementation(UmlElement... elements) {
classDiagram = new MyClassDiagram();
addMacro(elements); //class, interface
addMicro(elements); //attribute,operation,association,gen,interfaceReal
addNano(elements); //parameter, associationEnd
}
private void addNano(UmlElement[] elements) {
for (UmlElement e : elements) {
if (e instanceof UmlParameter) {
classDiagram.addParameter((UmlParameter) e);
} else if (e instanceof UmlAssociationEnd) {
classDiagram.addAssEnd((UmlAssociationEnd) e);
}
}
}
-
结构的建立
为便于执行指令,将官方包提供的UmlClass
,UmlInterface
等类的功能进行扩展,成为MyClass
,MyInterface
等类的属性。
private MyClass parent;
private ArrayList<UmlAttribute> attributes;
private HashMap<String, MyOperation> operations;
private HashMap<String, MyInterface> interfaces; //implemented interfaces
private HashMap<String, MyAssociation> associations; //associations with others
private UmlClass umlClass;
private ArrayList<MyClass> children;
private HashMap<String, String> implementInterfaceMap;
-
指令的处理
为避免MyImplementation
类过于臃肿冗长,将每一步操作都实现在下属的MyClass
,MyInterface
类中,只保留大的操作步骤,使得三次作业中MyImplementation
类的代码行数始终控制在330行以内。
1.2 第十四次作业——建立顺序图、状态图
增加类MySequenceDiagram
,MyStateDiagram
,MyEndPoint
,MyGeneralLifeline
,MyInteraction
,MyLifeline
,MyRegion
,MyState
,MyStateMachine
,MyTransition
.
-
顶层结构
本次作业建立起三种UML图的结构,在MyImplementation
顶层类中只有三个属性:
private final MyClassDiagram classDiagram;
private final MySequenceDiagram sequenceDiagram;
private final MyStateDiagram stateDiagram;
类图的指令就调用MyClassDiagram
的方法处理,其余两种图同理。
-
降低类之间的耦合
为了保证类之间的低耦合,采用层层向内调用的方法,以getStateCount()
为例:
//MyImplementation.java
public int getStateCount(String s)
throws StateMachineNotFoundException, StateMachineDuplicatedException {
MyStateMachine sm = stateDiagram.getStateMachine(s);
return sm.getStateCount();
}
//MyStateMachine.java
public int getStateCount() {
return region.getStateCount();
}
//MyRegion.java
public int getStateCount() {
return states.size();
}
-
关键状态的判断
本次作业最复杂的指令就是关键状态的判断指令。对此的实现为:
采用DFS遍历得到一个双层ArrayList
保存从初始状态到最终状态的所有路径。
private ArrayList<ArrayList<MyState>> allPaths;
若某一状态在所有路径中,则该状态为关键状态。
1.3 第十五次作业——规范性验证
本次作业没有添加新的类.
-
循环继承和重复继承
以接口的循环继承和重复继承为例,在MyInterface
中定义递归方法,分别使用DFS向上遍历所有接口,第一次DFS当检测到和this
ID相同的接口时说明有循环继承,第二次DFS当检测到当前遍历到的接口ID已经遍历过时,说明有重复继承。
二、架构设计思维及OO方法理解的演进
经过了十二次的代码训练,我对架构设计和OO思维都有了更深刻的理解。
第一单元时我还对OO思想所知甚少,基本上是面向实验代码编程,在整体编完后再反复阅读代码,才窥见到递归下降和表达式,项,因子层次化建模的精妙之处。方法复杂度的控制基本上全靠IDEA的Extract Method功能,都是先编好一个冗长的方法再去想办法精简,且顶层设计思维缺失,最后的metrics里复杂度居高不下,也花费了大量时间。
第二单元的多线程我以前从未接触过,理论课讲授JVM的线程原理时需要花一些时间才能理解,或许若是事先学习了OS的进程管理部分会更好理解一些。那时最常见的错误就是死锁,也就是在那时我初步学会了使用设计模式来让我的代码更加清晰。在不断调试的过程中,我逐渐明白了类之间的协作和解耦的意义。
第三单元JML主要要求不在于架构,而是细致读代码和算法复杂度的控制。JML虽然难以读懂,但一旦读懂基本不会出现正确性问题。这个单元的代码很值得学习,虽然不需要我们去设计,但编完代码再纵观全局,可以体会到好的架构设计带来的好处。
第四单元我的层次化设计思想有了很大地进步,开始主动地设计自己代码的层次、主动进行类的解耦。我真切地看到了自己OO思维和架构设计思维的提升。
三、测试理解与实践的演进
第一单元由于完成作业占用时间较多,没有尝试构建评测机和数据生成器,采用手动构造边界数据的方法进行测试,但由于覆盖性不够高,导致还是出现了bug。
第二单元构造了简易的数据生成器进行测试,检测到了一定数量的bug,但由于编写时考虑不周,仍未做到很高的覆盖率。
第三单元编写了数据生成器,实现了参数控制构造有针对性的数据,并和同学进行对拍,另外所幸本单元数据较为友好,数据覆盖率得到了很大的改善。
第四单元由于数据构造难度上升,采取手动构造UML图的方法。
四、课程收获
-
建立了OO的思维,对代码架构的理解加深
-
了解了多线程的基本原理和实现方法,可以进行一般的同步控制。
-
了解了应用设计模式进行编程的重要性和好处。
-
掌握了测试的重要性和一般方法,学会构造简易的数据生成器和对拍程序。
-
提升代码能力、算法能力和复杂度优化能力。
-
充分体会到多人合作编写程序时做好接口的重要性,例如在U4中不需了解很多的上层官方包代码就可以进行核心功能的开发,避免了重复开发引起的效率低下。
-
切身实践了小型工程性代码的编写,这与之前的算法题和微型程序的编写步骤有一定区别。
-
了解到面向对象的优势和Java作为一门纯粹的面向对象语言编写复杂程序时的魅力。
五、改进建议
-
希望在第一单元之前做更多的铺垫,例如递归下降的介绍,个人认为第一单元难度跨度较大,即使完成了Pre,仍然在初次看到题时一头雾水。
-
希望在课上实验后公布答案或者评测结果,这样能够更清楚地发现自身问题。
-
给出一些数据测试的教程,第一二单元对测试还不够了解时不知道该从何下手编写评测机。
-
希望后两个单元的理论课可以更加实际,个人感觉后两个单元的理论课和作业有些脱节,联系不够紧密。