BUAA_OO第四单元博客作业
BUAA_OO第四单元博客作业
一、架构设计
本单元主要考察类图、时序图、顺序图的规范表达。并根据一定的规则建立自己的结构层次,最后以此判断UML输入是否合法。下面详细介绍类图的结构
类图结构
在类图中新建MyClass
、MyInterface
、MyOPeration
类来分别表示类、接口、方法函数体。更加方便地存储和查找元素所在地位置。例如将UmlAttribute
以HashMap地形式存储在MyClass
类中,依据是UmlAttribute
地parent_id。这样就可以快速地得知某类地元素的个数及其具体性质,而不是通过遍历所有元素的parent_id进行查询了。
从而建立起一种类似树状的结构,从一个节点(MyClass
)查到其所有的属性(UmlAttribute
、MyInterface
、MyOPeration
)等,再根据此属性(MyOperation
)进行递推,得到更下一层的内容(UmlParameter
),就可以得到这个节点拿下的所有内容。
-
MyClass
:类包含了类的元素、函数、父类、相关联的引用以及实现的接口等。通过HashMap的存储这些信息。
private final UmlClass umlClass; private MyClass superClass = null; private final ArrayList<UmlAttribute> attributes = new ArrayList<>(); private final HashMap<String, ArrayList<UmlAttribute>> name2attribute = new HashMap<>(); private final ArrayList<MyOperation> operations = new ArrayList<>(); private final HashMap<String, ArrayList<MyClass>> name2aClass = new HashMap<>(); private final HashMap<String, ArrayList<MyInterface>> name2aInterface = new HashMap<>(); private final ArrayList<MyClass> associatedClass = new ArrayList<>(); private final ArrayList<MyInterface> associatedInterface = new ArrayList<>(); private final ArrayList<MyInterface> implementInterface = new ArrayList<>();
-
MyInterface
:接口包含接口中的属性、父类接口、相关联的引用以及函数方法。通过HashMap以name为键值指向对应的类。
private final UmlInterface umlInterface; private final ArrayList<MyOperation> operations = new ArrayList<>(); private final ArrayList<UmlAttribute> attributes = new ArrayList<>(); private final ArrayList<MyInterface> superInterface = new ArrayList<>(); private final HashMap<String, ArrayList<MyClass>> name2aClass = new HashMap<>(); private final HashMap<String, ArrayList<MyInterface>> name2aInterface = new HashMap<>(); private final ArrayList<MyInterface> associatedInterface = new ArrayList<>(); private final ArrayList<MyClass> associatedClass = new ArrayList<>();
-
MyOPeration
:方法包含参数等,通过ArrayList存储
private final UmlOperation umloperation; private UmlParameter returns = null; private final ArrayList<UmlParameter> params = new ArrayList<>();
-
UML图
顺序图UML
状态图UML
二、四个单元中架构设计及OO方法理解的演进
第一单元
内容为表达式求导,主要学习的是继承、接口、容器的使用。由于第一次接触OO和java,对其中的一些原理和规范在理解上有一些模糊,所以做的比较困难。
但是从中学到了面向对象的一些基本用法,通过构建新的类,并建立每个类之间的联系,进而形成继承的层次结构,再通过一个父类的容器进行统一的管理,就可以实现对同一父类、不同子类的操作。同时在每个子类的内部会写有专门的重载(overloading)方法,在吊桶父类方法时便会自动调用子类特殊的方法,从而实现对不同对象不同的求导法则,这便体现了多态的好处,也让我更好的理解了多态的用法。
第二单元
内容为电梯调度,主要的难点是多线程的调试以及任务分配的算法。同样是第一次接触多线程,在理解其原理以及用法上花费了一定的时间和精力。帮助最大的是我在研讨课上的一次分享,使我对多线程有了更加深刻的了解,真正的理解了共享对象的作用以及其维护方法(临界区),同时学会了控制不同线程的等待(wait)与唤醒操作(notify)。这让我掌握了不同线程之间存在的逻辑顺序。在电梯调度方面,我采用了LOOK
算法,在多天体任务分配方面,我采用了均分的思想,从而使性能得到了一定的优化。
第三单元
内容为JML
,整体难度偏小,主要是想让我们了解在高端编程中java语言的规范,通过严谨无二义性的JML
语言来代替自然语言,能够使庞大的工程拆分成具体的、精确的小程序。
但是在作业中还是存在一定的问题,例如CTE、RTE等超时问题。问题主要出现在对JML
语言的直接搬抄,没有进行理性思考的结果。正确的根据JML
书写程序的过程是:读懂JML
,然后将其转化为无二义性的实际问题(自然语言),再通过一定的算法降低需要多重循环的语句的复杂度(一般采用空间换时间的方法)。在此单元中我学会了JML
的规范,掌握了转换成无二义性java语言的能力,学到了如何有效的降低算法的时间复杂度(如差分集)。
第四单元
内容为UML
图,难度偏低,主要学习了UML
图的规范,以及在工程上的表示方法,开阔了眼界。除此之外,掌握了通过构建新类对多个元素进行归一、分类的能力,从而达到快速查询的效果。
三、四个单元中测试理解与实践的演进
第一单元
测试的方法主要是对拍机,数据随机生成,在时间充裕的情况下,根据讨论区自学了python中函数求导以及比较不同函数是否相等的功能,这为对拍测试提供了极大的便利。
但是由于测试数据的覆盖率较低,对一些隐藏问题没有测试到,从而导致了强测中出现超时的错误(后发现使递归的问题),这对我有一定的启示。
第二单元
多线程测试,这对我来说是一次巨大的挑战。根据讨论区的指导,通过C语言实现了定时输入的功能,对一个文档中的内容定时的读取,来模拟请求的随机到达。同时为了保证多线程可能出现的不稳定问题以及批量处理问题,我通过白那些.bat程序实现了对C语言文件的批量处理,如下
start cmd /k "echo testpoint 1: && cd ../Homework7/out/artifacts/Homework7_jar && timeInput.exe < input.txt | java -jar Homework7.jar && echo testpoint 1"
start cmd /k "echo testpoint 1: && cd ../Homework7/out/artifacts/Homework7_jar && timeInput.exe < input.txt | java -jar Homework7.jar && echo testpoint 1"
start cmd /k "echo testpoint 1: && cd ../Homework7/out/artifacts/Homework7_jar && timeInput.exe < input.txt | java -jar Homework7.jar && echo testpoint 1"
start cmd /k "echo testpoint 1: && cd ../Homework7/out/artifacts/Homework7_jar && timeInput.exe < input.txt | java -jar Homework7.jar && echo testpoint 1"
start cmd /k "echo testpoint 1: && cd ../Homework7/out/artifacts/Homework7_jar && timeInput.exe < input.txt | java -jar Homework7.jar && echo testpoint 1"
可以同时开启多个进程,有效的测试了进程的不稳定性,提高了测试的效率。
最重要的是因为多进程的不可复现性,采用打日志的成为了首选的方法,好的日志可以复现多个进程的切换顺序,可以更好的发现bug。当然,学会对多线程进行调试也是不可或缺的哦。
第三单元
Junit
测试,通过编写Junit
程序,对每一个方法进行全面覆盖的测试,测试代码具体如下
@Test
void contains() throws EqualPersonIdException {
System.out.println("contains");
MyNetwork n = new MyNetwork();
Person a = new MyPerson(1, "1", 1);
n.addPerson(a);
Assert.assertEquals(n.contains(a.getId()), true);
}
void queryBlockSum() throws EqualPersonIdException, PersonIdNotFoundException, EqualRelationException {
System.out.println("queryBlockSum");
MyNetwork n = new MyNetwork();
Person a = new MyPerson(1, "1", 1);
Person b = new MyPerson(2, "2", 2);
Person c = new MyPerson(3, "3", 3);
Person d = new MyPerson(4, "4", 4);
Person e = new MyPerson(5, "5", 5);
n.addPerson(a);
n.addPerson(b);
n.addPerson(c);
n.addPerson(d);
n.addPerson(e);
n.addRelation(b.getId(), c.getId(), 10);
n.addRelation(c.getId(), d.getId(), 20);
n.addRelation(a.getId(), e.getId(), 30);
Assert.assertEquals(n.queryBlockSum(), 2);
}
即通过对每个方法进行确定样例、确定结果的测试,这样有效的实现了多个样例的重复测试,实现了方法测试的全覆盖,这是工程上较为通用的测试方法,具有很强的严谨性。
第四单元
利用StartUML软件进行测试。将.mdj导入软件中,通过自行绘制特定的类图、顺序图、状态图来改变.mdj文件,再通过java包、命令行导出成输入样例,进而对程序进行特定、细致的测试。
四、课程收获
通过一学期的OO学习,我掌握了面向对象的本质内容,能供熟练的书写java程序,使用特定的容器以及java自带的处理函数(是真的好用),同时对java的原理知识有了一定程度的理解,这对之后的代码书写有很大的帮助。
并且通过第三、四单元的训练,开阔了我的视野,让我明白了java的书写规范,以及在团队合作中,无二义性的重要程度。
让我收获最多的是课程的循序渐进的体制,让我明白了代码不仅要能跑出正确的结果,更要有良好的可延展性,良好的架构。这边要求我在书写代码之前,要对代码架构有充分的构思,要想好在动手打码,这点在我看来比任何的实践、理论知识都要重要的,这直接决定了你的代码能走多远、能走多稳健。
五、课程建议
讲真,OO的课程虽然安排的挺紧,但是体验感还是不错的。说到建议的话,有以下六点
- 加强理论课与课程作业的联系性。
- 及时公布上机实验的答案。
- 加强研讨课的积极性,可以开展研讨课的其他内容,如对理论或是课程作业中某一特定问题的详细解答。
- 让同学们自主选择研讨课的内容,同时增加研讨课反馈机制。
- 尽可能地排除课程作业要求的二义性(不得不说,助教们做的真心不错)。
- 适当公开同一单元下一次作业的部分内容,这样可以将对同学们的重构概率,减少时间的浪费(重构真是痛苦)。