虽说是第二次实验,但近期的确事情有点多,Java的学习进度也有些搁置,所以这次实验依旧困难重重。
本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象 编程(OOP)技术实现 ADT。具体:
根据描述识别对应ADT;
设计ADT规约并评估质量;
根据规约设计测试用例;
ADT的泛型化;
根据规约设计ADT的不同实现,针对每种实现设计其表示、表示不变性、抽象过程;
使用OOP实现ADT,并判定不变性是否违反、各实现是否存在表示泄漏;
测试ADT的实现并评估测试的覆盖度;
使用ADT及其实现,为应用问题开发程序;
在测试代码中,能够写出 testing strategy 并据此设计测试用例。
3、实验过程
3.1 Poetic Walks
实现抽象数据类型Graph,在此基础上实现GraphPoet,一个通过单词亲和图生成诗歌的类。
3.1.1 Get the code and prepare Git repository
3.1.2 Problem 1: Test Graph <String>
测试策略:方法与等价类
3.1.3 Problem 2: Implement Graph <String>
3.1.3.1 Implement ConcreteEdgesGraph
Edge类:
//fields
private int weight;//边的权重
private L source;//起点
private L target;//终点
//constructor
public Edge(L source, L target, int weight):增加一个edge
//methods
public void setweight(int weight):改变weight
public L source():返回source
public L target():返回target
public int weight():返回weight
//toString()
public String toString():返回字符串表示的edge,自动生成的就行
ConcreteEdgesGraph类:
//fields
protected final Set<L> vertices = new HashSet<>();//存储所有顶点
private final List<Edge<L>> edges = new ArrayList<>();//存储所有边
//methods
public boolean add(L vertex):增加一个顶点
public int findedge(L source, L target):找到边在list中的位置,返回一个index
public int set(L source, L target, int weight):增加一条有向边
public boolean remove(L vertex):移除一个顶点
public Set<L> vertices():返回包含所有顶点的集合
public Map<L, Integer> sources(L target):返回某个顶点为终点的所有边
public Map<L, Integer> targets(L source):返回某个顶点为起点的所有边
3.1.3.2 Implement ConcreteVerticesGraph
Vertex类:
//fields
private L name;//顶点的名字
private Map<L, Integer> allsource = new HashMap<>();//返回该顶点为起点的所有边
private Map<L, Integer> alltarget = new HashMap<>();//返回该顶点为终点的所有边
//constructor
public Vertex(L name):增加一个vertex
//methods
public L name():返回顶点名字
public Map<L, Integer> getsource():返回allsource
public Map<L, Integer> gettarget():返回alltarget
public void setsource(L source, int weight):在allsource中增加一个映射
public void settarget(L target, int weight):在alltarget中增加一个映射
//toString()
public String toString():自动生成
ConcreteVerticesGraph类:
//fields
private final List<Vertex<L>> vertices = new ArrayList<>();//储存所有顶点
//methods
public L name():返回顶点名字
public Map<L, Integer> getsource():返回allsource
public Map<L, Integer> gettarget():返回alltarget
public void setsource(L source, int weight):在allsource中增加一个映射
public void settarget(L target, int weight):在alltarget中增加一个映射
3.1.4 Problem 3: Implement generic Graph<L>
3.1.4.1 Make the implementations generic
将所有string改为L
3.1.4.2 Implement Graph.empty()
3.1.5 Problem 4: Poetic walks
3.1.5.1 Test GraphPoet
3.1.5.2 Implement GraphPoet
//fields
private final Graph<String> graph = Graph.empty();
//methods
public GraphPoet(File corpus) throws IOException():从corpus中读取原文,处理后存在graph中。
public String poem(String input): public String poem(String input):基于graph将input改为诗歌并返回。
3.1.5.3 Graph poetry slam
3.1.6 使用Eclemma检查测试的代码覆盖度
3.1.7 Before you’re done
将文件放在本地仓库,然后输入指令
Git add .
Git commit
Git push
我的项目的目录结构树状示意图:
3.2 Re-implement the Social Network in Lab1
利用Lab1中已经实现的Social Network来重新编写。
基于我在 3.1 节 Poetic Walks 中定义的 Graph<L>及其两种实现,重新实现 Lab1 中 3.3 节的 FriendshipGraph 类。
3.2.1 FriendshipGraph类
//fields
private final Graph<Person> graph = Graph.empty();
//methods
public boolean addVertex(Person person):增加一个人到关系网中
public boolean addEdge(Person source, Person target, int weight):在关系网中增加一个关系
public int getDistance(Person a, Person b):获取关系网中两个人的距离,使用BFS
3.2.2 Person类
//fields
private String name;//人的名字
public int distance;//方便BFS而设置的距离
//constructor
public Person(String name):增加一个人
//methods
public String name():返回name
public int distance():返回distance
3.2.3 客户端main()
沿用之前的main函数即可,仅仅对addEdge多了一个参数。
3.2.4 测试用例
3.2.5 提交至git仓库
提交方法同3.1.7。
我的项目的目录结构树状示意图:
4、遇到的困难及解决方法
遇到的难点 | 解决途径 |
Test中的test文件无法正常运行 | 将test文件夹重新建立build path |
P1的VertexGraph中remove ()方法无法正确实现 | 将List的remove()方法使用index删除,即可顺利删除了, 而之前使用object删除未成功 |
5、实验中的收获、教训、感受
5.1 收获与教训
必须要继续学习java,不然往后越来越难,很难靠自己完整编程。
5.2 感受
1面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?
后者感觉对用户更友好。
2使用泛型和不使用泛型的编程,对你来说有何差异?
暂时没有感受到,还需对泛型进行进一步的学习和体会。
3在给出ADT的规约后就开始编写测试用例,优势是什么?你是否能够适应这种测试方式?
优势是面向测试的编程,有点逆推法的感觉,需要慢慢适应。
4P1设计的ADT在多个应用场景下使用,这种复用带来什么好处?
减少内存使用,也能减少程序员代码编写时间。
5P3要求你从0开始设计ADT并使用它们完成一个具体应用,你是否已适应从具体应用场景到ADT的“抽象映射”?相比起P1给出了ADT非常明确的rep和方法、ADT之间的逻辑关系,P3要求你自主设计这些内容,你的感受如何?
不太适应,这次还是依靠了一部分Lab1的代码知识。
6为ADT撰写specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?
能对编码有个清晰的认识,以后我可能不会写出来,但会在脑子里过一下。
7关于本实验的工作量、难度、deadline。
工作量对于我这个java小白来说真的很多,难度很大,deadline因为和计算机系统的期末考试撞了,所以很难受。
8《软件构造》课程进展到目前,你对该课程有何体会和建议?
刚刚步入软件构造的课堂,还算是个软构小白。到现在我已经聆听了几堂课,愈发觉得软件构造是一个庞大的工程,它让我跳出了基本的programming和coding,从一个更高的角度来俯视整个软件构造的过程。