目录
Get the code and prepare Git repository
Implement ConcreteVerticesGraph
Problem 3: Implement generic Graph
Make the implementations generic
Re-implement the Social Network in Lab1
实验目标概述
本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象
编程(OOP)技术实现 ADT。具体来说:
⚫ 针对给定的应用问题,从问题描述中识别所需的 ADT;
⚫ 设计 ADT 规约(pre-condition、post-condition)并评估规约的质量;
⚫ 根据 ADT 的规约设计测试用例;
⚫ ADT 的泛型化;
⚫ 根据规约设计 ADT 的多种不同的实现;针对每种实现,设计其表示
(representation)、表示不变性(rep invariant)、抽象过程(abstraction
function)
⚫ 使用 OOP 实现 ADT,并判定表示不变性是否违反、各实现是否存在表
示泄露(rep exposure);
⚫ 测试 ADT 的实现并评估测试的覆盖度;
⚫ 使用 ADT 及其实现,为应用问题开发程序;
⚫ 在测试代码中,能够写出 testing strategy 并据此设计测试用例。
实验环境配置
IDEA自带代码覆盖率工具,只需右键单击测试文件,选择Run with Coverage即可:
以实验一中P3的测试为例:
在这里给出你的GitHub Lab2仓库的URL地址(Lab2-学号)。
git@github.com:ComputerScienceHIT/HIT-Lab2-120L020709.git
实验过程
请仔细对照实验手册,针对两个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
Poetic Walks
此实验的目的是练习设计、测试和执行ADT。该阶段给出了一个图的接口,要求建立一个边图类一个点图类来分别实现该图的接口,在里面实现一系列方法,同时需要满足泛型要求。在完成了两种实现后,任选一种实现形式完成自动扩展诗歌的任务。
Get the code and prepare Git repository
从GitHub获取该任务的代码:
git clone https://github.com/rainywang/Spring2022_HITCS_SC_Lab2/tree/master/P1
使用git管理本地开发:git add和git commit完成版本更新
完成后push到github上
Problem 1: Test Graph <String>
思路:对Graph<string>接口中的方法进行测试,根据方法的规约了解Graph类的设计要求。
测试策略(等价类划分):
1.对add方法:点在图中/点不在图中
2.对set方法:
边在图中:权值>0(需要更新权值);=0(删除边);<0(非法输入)
边不在图中但顶点在图中:权值>0;=0(删除边);<0
边和顶点都不在图中:权值>0;=0(删除边);<0
3.对remove方法:
点在图中/点不在图中
4.对vertices方法:
点集为空/点集不空
5.对sources方法:
作为参数的顶点存在源点(返回非空)/作为参数的点不存在源点(返回为空)
6.对targets 方法:
作为参数的顶点存在目标点(返回非空)/作为参数的点不存在目标点(返回为空)
结果:实现两种类后运行测试用例,通过。
Problem 2: Implement Graph <String>
Implement ConcreteEdgesGraph
(1)设计Edge类:
边应该包含三个信息:源点,目标点,权值
方法包含getSource()、getTarget()和getWeight(),要求给出Edge()的构造方法和checkRep方法。并完成spec、AF、RI、safety from Rep Exposure的撰写。重写equals(),hashCode(),toString()方法。
(2)测试Edge类:
对得到三要素的返回值/tostring方法:创建一个实例,返回值进行对比即可
对equals方法:相等/不相等
按照规约利用Edge实现ConcreteEdgesGraph
Implement ConcreteVerticesGraph
(1)设计Vertex类:
顶点应该包含:顶点的标签,该点指向的顶点集,指向该点的顶点集
方法包含getSource()、getTarget()和getWeight(),要求给出Vertex()的构造方法和checkRep方法。并完成spec、AF、RI、safety from Rep Exposure的撰写。重写toString()方法。Mutable类型数据,所以不用重写equals(),hashCode()方法。
对getLabel()方法由于是不变型的数据,所以可以直接返回,而其他的getMethod为防止表示泄露需要进行防御式拷贝。
(2)测试Vertex类:
对得到三要素的返回值/tostring方法:创建一个实例,返回值进行对比即可
对equals方法:相等/不相等
(3)按照规约利用Vertex实现ConcreteVerticesGraph
这里一开始set函数我选择直接调用了vertices动态数组的contains方法,由于contains方法是调用了内部equals方法来判断是否相等,而对于用Vertex类型来说,其为可变类型,可以通过equals方法直接判断是否地址相同即可
这就属于是没有看清楚source传参是泛型变量了,所以我的操作其实没有任何依据,所以选择用for循环遍历。
Problem 3: Implement generic Graph<L>
用类实现接口
Make the implementations generic
将前面已经实现的String类型全部改为泛型L
Implement Graph.empty()
生成空图
采用ConcreteEdgesGraph<L>来实现Graph<L>:
为了测试Graph<L>的正确性,在GraphStaticTest中为IntegerGraph和DoubleGraph设计了几个简单的测试用例,最终所有测试用例都通过了:
Problem 4: Poetic walks
Test GraphPoet
为了方便测试,引入observer,分别是vertices()、sources()和targets()。
完成对GraphPoet的测试用例的书写,先进行等价类划分,写出测试策略,然后按照“覆盖每个取值”的策略为每个方法构造测试用例。
Implement GraphPoet
完成GraphPoet的AF、RI、safety from Rep Exposure,并实现各个方法。
Graph poetry slam
用一句诗为例测试构造了一个句子。
Before you’re done
请按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的说明,检查你的程序。
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
先进入工作区的位置,然后在git bash中输入“git init”建立本地仓库,再输入“git remote add lab2 https://github.com/ComputerScienceHIT/HIT-Lab2-1190201421”添加远程仓库,然后输入“git add <filename>”,“git commit -m “***””,“git push -u lab2 master”即可向远程仓库提交代码。
在这里给出你的项目的目录结构树状示意图。
Re-implement the Social Network in Lab1
在这里简要概述你对该任务的理解。
运用已经实现的Graph类重新实现Lab1中的FriendshipGraph。
FriendshipGraph类
给出你的设计和实现思路/过程/结果。
复用已经设计出来的Graph<L>实现FriendshipGraph,选择用ConcreteEdgesGraph<L>的实现方式。除了要求的addVertex、addEdge和getDistance,还加入了checkRep、getPeople和getFriends,其中getPeople用于查看graph中的Person,getFriends用于查看Person a的朋友(单向关系)。便于操作。
按照ADT的设计方法,完善了Lab1中的FriendshipGraph,写出所有的spec、AF、RI、safety from Rep Exposure。
Person类
给出你的设计和实现思路/过程/结果。
继续使用Lab1中Person的实现由于朋友关系能交给graph去记录,故略去了Person中和friend相关的内容。同时,由于Person是一个immutable的类,对equals、hashCode和toString方法进行了重写,完善了spec、AF、RI、safety from Rep Exposure,实现了checkRep方法。
客户端main()
给出你的设计和实现思路/过程/结果。
按Lab1实验手册中提供代码为准。
测试用例
给出你的设计和实现思路/过程/结果,覆盖度报告。
按要求将Lab1中测试用例用于Lab2的测试。
提交至Git仓库
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
同上。
在这里给出你的项目的目录结构树状示意图。
实验进度记录
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。
不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。
日期 | 时间段 | 计划任务 | 实际完成情况 |
5.18 | 18:00-22:00 | 完成测试用例编写 | 按计划完成 |
5.20 | 17:30-21:50 | 完成Edge设计和ConcreteEdgesGraph | 有点轻敌,还有点累了,未能完成 |
5.22 | 8:00-12:00 | 完成到ConcreteVerticesGraph | 在set方法上出问题了,未能完成 |
15:30-18:00 | 完成ConcreteVerticesGraph | 按计划完成 | |
5.22 | 19:30-22:00 | 完成GraphPoet的设计和测试用例 | 在文件管理操作和理解题意上出了问题,未完成 |
5.24 | 18:00-22:00 | 完成到Poetic walks | 完成但不完善 |
5.27 | 18:00-22:00 | 完成P2 | 按计划完成 |
5.29 | 18:00-22:00 | 在前面零散的设计的基础上撰写实验报告 | 按计划完成 |
实验过程中遇到的困难与解决途径
遇到的难点 | 解决途径 |
对文件读写方法不熟悉 | 上网搜索 |
题意搞不清楚 | 重看实验课,向同学请教 |
Github使用不熟悉 | 阅读手册,多次尝试 |
实验过程中收获的经验、教训、感想
实验过程中收获的经验和教训
准确把握题意,对实验的任务量和目标有全面的掌握,有利于对规约、AF、RI的撰写
类未实现,测试先行,好的测试的设计对类的实现有着重要的指导意义。
泛型的使用追求一个泛字,要求不能有先入为主的判断,否则会对测试用例运行时的心态造成打击。
针对以下方面的感受
1. 面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?
前者更加抽象,设计出的ADT能在多个应用场景下复用,但是开发难度较大,后者更为具体,自由度更高,但可复用性较差
2. 使用泛型和不使用泛型的编程,对你来说有何差异?
使用泛型时更为抽象,而且容易踩坑,先用一个具体的类型代入设计还是能够有帮助的
3. 在给出ADT的规约后就开始编写测试用例,优势是什么?你是否能够适应这种测试方式?
对类的实现有重要的指导意义,一开始的工作确实变得更枯燥而且感觉没什么成就,但是到编写类时确实很有裨益。可以慢慢适应。
4. P1设计的ADT在多个应用场景下使用,这种复用带来什么好处?
可以有自己的抽象类库,开发效率更高,可能什么时候想实现一个什么类,就对自己未来可能有帮助。
5. 为ADT撰写specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?
便于他人理解代码,也便于检查自己程序的实现,保证程序的安全性。
6. 关于本实验的工作量、难度、deadline。
相对Lab1的难度更大,工作量也更多,不过庆幸没有以前的实验那么多,deadline还算合理。
7. 《软件构造》课程进展到目前,你对该课程有何体会和建议?
课程让我意识到一个计算机系的学生不具备编程能力,害怕编程确实听离谱的,让我有更大的欲望去多做实验,同时,课上的知识也对实验过程有重要的指导作用,不过由于以前只注重理论,也让我认识到自己的不足,课程安排本身没什么问题,就是放在学期背景下压力还是有的。