软件构造实验2感想
由于本人代码能力一般,本文主要想谈一下对Lab2的一些感悟,希望能对学弟学妹有一点帮助
首先在时间安排方面,这也是非常重要的一点,一定要早点开始!软构实验的任务量对于不太熟悉java来说还是不小的,特别是最后的ddl大概率还会跟考试撞车,所以如果想从容不迫地复习考试,一定一定要提前写。
其次就是实验方面的一些体会。这个实验内容总体上很不错的,一步步层层递进,到最后实现一个自己的客户端功能。提一个小建议,建议把基于点的图和基于边的图换一下顺序,这样可能上手更快一些。
从具体内容看,本次实验涵盖了ADT,OOP,泛型...最近课堂上讲解的关键内容,同时还练习了优先设计测试的设计模型(这个真的很有用,能帮助你快速看懂实验内容),能够加深对这些内容的体会。建议如果对这些内容不是很熟悉的话,先复习一下讲义再尝试进行实验。
在IDE方面,IDEA和Eclipse这两种IDE功能都非常强大,笔者实验1是用Eclipse进行的,在身边同学的推荐下,实验2尝试了IDEA,可能IDEA的补全功能更加舒服一点(doge)。总之如果只是进行简单的实验IDE十分强大的功能大部分都没有被使用到,只有平常多码代码,多探索才能使适合自己的IDE成为更有利的工具。所以这两种IDE也可以都尝试一下,看看自己更适合哪款。
最后附上实验内容的一些关键点可供参考:
3.1 Poetic Walks
本问题目的在于实践 ADT 的规约设计和 ADT 的多种不同的实现,先使用
具体类型 String 进行编程,之后转换为泛型 L。之后使用开发好的 ADT 进行应
用。并在每一步都进行测试,进一步练习基于 Junit 的测试方法,并根据覆盖率
完善测试用例。
3.1.1 Get the code and prepare Git repository
使用 git clone 指令将 GitHub 上的代码包克隆到本地,由于需要修改项目配
置,所以手动粘贴代码包到 IDE 的工作集下。通过在项目文件夹下使用 git init
指令即可完成本地仓库的建立。
3.1.2 Problem 1: Test Graph <String>
以下各部分,请按照 MIT 页面上相应部分的要求,逐项列出你的设计和实现
思路/过程/结果。
实现思路:我的测试策略是对每一个需要测试的函数进行输入空间的划分,
然后根据输入空间的划分以尽可能覆盖所有情况的策略进行测试。
具体设计:
1. //boolean add(L vertex)
2. test add 策略:
3. graph: 1、graph 为空
4. 2、graph 非空
5. 参数 L vertex: 1、新的点
6. 2、已经存在于 graph 中的点
7.
8. //int set(L source,L target,int weight)
9. test set 策略:
10. graph: 1、graph 为空
11. 2、graph 非空
12. 参数 L source: 1、source 是新的点
13. 2、source 已经在 graph 中
14. 参数 L target: 1、target 是新的点
15. 2、target 已经在 graph 中
16. 参数 int weight: 1、weight = 0
17. 2、weight > 0
18.
19. //boolean remove(L vertex)
20. test remove 策略:
21. 参数 L vertex: 1、vertex 为新的点
22. 2、vertex 已经在 graph 中,但没有点和它相连
23. 3、vertex 已经在 graph 中,且有点和它相连
24.
25. //Set<L> vertices()
26. test vertices 策略:
27. graph: 1、graph 是空图
28. 2、graph 非空
29.
30. //Map<L,Integer> sources(L target)
31. test sources 策略:
32. graph: 1、graph 为空
33. 2、graph 非空
34. 参数 L target: 1、target 是新的点
35. 2、target 是 graph 中的点,但是没有边指向它
36. 3、target 是 graph 中的点,有边指向它
37.
38. //Map<L,Integer> targets(L source)
39. test targets 策略:
40. graph: 1、graph 为空
41. 2、graph 非空
42. 参数 L source: 1、source 是新的点
43. 2、source 是 graph 中的点,但是没有边以它为起点
44. 3、source 是 graph 中的点,且有边以它为起点
3.1.3 Problem 2: Implement Graph <String>
以下各部分,请按照 MIT 页面上相应部分的要求,逐项列出你的设计和实现
思路/过程/结果。
3.1.3.1 Implement ConcreteEdgesGraph
实现思路:ConcreteEdgesGraph 类为 Graph 接口的实现,所以至少需要对接
口中的所有方法进行重写,重新又需要借助辅助类 Edge 的帮助,根据业务逻辑
可初步确定 Edge 类中所需的方法。在完全对具体类型 String 实现的基础上,实
现泛型 L 的设计。
具体设计:
1.Edge 类的成员函数如下:
具体的方法如下:
checkRep: 检查不变量,边的权值>0,边的源顶点和目标顶点非空
getSource: 返回边的源顶点
getTarget: 返回边的目标顶点
getWeight: 返回边的权值
toString: 按照指定格式打印边,比如”a->b 权值为:1”
对于 AF:
对于 RI:
对于安全的问题:
软件构造课程实验报告 实验 2:抽象数据类型 ADT 与面向对象编程 OOP
5
2)测试策略:对所有情况进行等价类的划分,然后尽可能覆盖
3)Edge 类实现和测试:
由于完整代码太多现取一部分截图如下:
4)ConcreteEdgesGraph 类的设计
成员变量和成员函数如图所示:
软件构造课程实验报告 实验 2:抽象数据类型 ADT 与面向对象编程 OOP
6
对于 AF:
对于 RI:
具体的规约方法如下:
对于安全问题:
5)实现 ConcreteEdgesGraph 类和它的测试
由于完整代码太多,截取部分的代码如下:
软件构造课程实验报告 实验 2:抽象数据类型 ADT 与面向对象编程 OOP
7
6)运行测试,全部通过:
7)查看覆盖率,方法覆盖率 100%,行覆盖率达到 97%:
3.1.3.2 Implement ConcreteVerticesGraph
1)Vertex 类的设计
Vertex 类的成员函数如图所示:
对于 AF:
软件构造课程实验报告 实验 2:抽象数据类型 ADT 与面向对象编程 OOP
8
对于 RI:
对于安全问题:
2)实现 Vertex 类和它的测试
完整代码太多,截取部分代码如图所示:
3)ConcreteVerticesGraph 类的设计
ConcreteVerticesGraph 类成员函数如图所示:
软件构造课程实验报告 实验 2:抽象数据类型 ADT 与面向对象编程 OOP
9
对于 AF:
对于 RI:
对于安全问题:
4)实现 ConcreteVerticesGraph 类和它的测试
全部代码太多,截取部分代码截图如下:
5)运行测试,测试全部通过:
软件构造课程实验报告 实验 2:抽象数据类型 ADT 与面向对象编程 OOP
10
6)查看覆盖率,方法覆盖率 90%,行覆盖率达到 86%:
3.1.4 Problem 3: Implement generic Graph<L>
将已有的两个 ConcreteEdgesGraph<String>,ConcreteVerticesGraph<String>
的实现改为 Graph<L>的泛型实现,转换后的类的声明如下:
3.1.4.1 Make the implementations generic
将 Vertex 和 Edge 也转化成泛型实现:
软件构造课程实验报告 实验 2:抽象数据类型 ADT 与面向对象编程 OOP
11
并 对 类 方 法 的 实 现 修 改 , 使 其 支 持 泛 型 。 将 ConcreteEdgesGraph 及
ConcreteVerticesGraph中用String声明的变量修改为L,并且在声明类的时候,
使用泛型 L。
实现后具体类的修改后,对其测试,发现测试全部通过。且覆盖率仍保持不变:
3.1.4.2 Implement Graph.empty()
1)使用 ConcreteEdgesGraph 作为返回对象构建新图,以实现 Graph.empty()
函数:
2)完成 GraphStaticTest 测试:
具体思路为分别使用 Double 和 Long 作为泛型 L 的具体实现来进行测试:
软件构造课程实验报告 实验 2:抽象数据类型 ADT 与面向对象编程 OOP
12
3)完成测试用力的编写后,具体测试效果如下:
3.1.5 Problem 4: Poetic walks
任务分析:本任务是先将给定的语料生成图结构,具体要求是相邻的单词间用一
条有向边连接,然后给定一个输入字符串,通过在图中判断它们之间是否有
bridge 来对字符串进行扩充。
3.1.5.1 Test GraphPoet
具体的测试策略如下:
1. 对于构造器:
2. 1、传入不存在的文件 2、传入的文件为空
3. 3、传入的文件只有一行 4、传入具有多行的文件
4.
5. 对于 poem 函数:
6. 1、传入的字符串为 null 2、传入的字符串!=null,但只有一个单词
7. 3、传入的字符串!=null,不止一个单词
8.
9. 对于 toString 函数:
10. 1、graph 为空 2、graph 不为空,但没有边 3、graph 有顶点有边
3.1.5.2 Implement GraphPoet
1)GraphPoet 的结构分析具体结构如下:
对于 AF:
软件构造课程实验报告 实验 2:抽象数据类型 ADT 与面向对象编程 OOP
13
对于 RI:
对于安全问题:
构造函数,传入文件名,根据相对路径读取文件,使用之前实现的方法完成图的
构建,产生异常时优雅的退出,部分主要代码如下:
对于 poem 方法,关键在于寻找 bridge,而 bridge 的寻找需要对源点和目标点
进行判断,当有多个符合要求的节点时,选择权值大的点作为桥,关键代码如下:
toString 方法就使用之前实现好的代码。
1)测试策略:
具体思路: 对 poem 传入参数不同情况下分别进行测试:当传入的文件不存在时;
当传入的语料库文件为空时;下面是语料库有一行或多行字符串时的情况。
toString 函数也使用类似的测试策略。
软件构造课程实验报告 实验 2:抽象数据类型 ADT 与面向对象编程 OOP
14
3)实际测试并测试覆盖率如下:
3.1.5.3 Graph poetry slam
自己找一首英文小诗放在文件 you.txt 下,输入字符串“fear losing”经过 poem
方法扩展后得到字符串”fear of losing“:
3.1.6 Before you’re done
请按照 http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done 的说
明,检查你的程序。
如何通过 Git 提交当前版本到 GitHub 上你的 Lab2 仓库。
在这里给出你的项目的目录结构树状示意图。
3.2 Re-implement the Social Network in Lab1
这个任务是要重新实现 Lab1 中的 Social Network,利用在 P1 中已经写
好的 Graph<L>接口来实现,尽量复用已经实现的函数。
软件构造课程实验报告 实验 2:抽象数据类型 ADT 与面向对象编程 OOP
15
3.2.1 FriendshipGraph 类
设计思路:对 ConcreteEdgeGraph 类进行继承,使用其已经实现的方法完成
需要实现的方法。
具体实现:addVertex 方法只需要简单的使用 add 方法即可实现。
对于 addEdge 方法,也只需要简单地调用 set 方法即可实现,注意两个人不
能相同:
3.2.2 Person 类
对于 AF:
人抽象为顶点
对于 RI:
顶点之间不能有相同的 name
对于安全问题:
Final 修饰,只能赋值一次不能修改
软件构造课程实验报告 实验 2:抽象数据类型 ADT 与面向对象编程 OOP
16
3.2.3 客户端 main()
直接使用 LAB1 的 main 函数即可。
3.2.4 测试用例
设计思路:对所有情况划分等价类,对所有方法进行测试:
查看覆盖率达到 100%:
3.2.5 提交至 Git 仓库
使用如下指令:git add P2
git commit -m”p2 completed”
git push origin_ssh master
项目树状图如下