【软件构造】HIT-Lab2经验总结教训

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

这次实验内容相较上一次难度提升了一个层次,虽然给的时间多但是三周内有三门考试,安排还是很紧凑,下面将讲一下我对Lab2和ADT的理解,以及实验中不多的注意点,一方面自己总结记录,另一方面方便学弟学妹们少走弯路。

一、插件工具的引入

一个是EclEmma,另一个是SpotBug(非必须,主要是用于对代码进行静态检测)。两个工具的导入都很简单,连接如下:
eclipse覆盖率插件——EclEmma的安装和使用
使用SpotBug进行静态代码检查

二、ADT的实现

首先,预习的时候最好先把实验手册和pdf先通读一遍,把实验各个类的spec,包括测试类都通读一遍,这样加深了对实验内容的理解,上手也比较方便。这次实验一方面是实验一的深入,也为下一章内容做铺垫。随着课程的深入,会对ADT的理解越来越深刻,然后对代码进行修改,再深入再理解的迭代过程,测试也是同理。
这部分编写的时侯,按照实验步骤即可,并无大的问题,先编写完备的测试代码,然后实现Edge和Vertex,再实现Graph的两个实现方法,这样的步骤能省去许多麻烦。在这个过程中,反复推敲的应该是对Edges或Vertex可变类型或不可变类型的各种操作是否安全,注意及时防御式拷贝或是返回不可修改的视图:示例如下:


//private final修饰属性
private final Set<L> vertices = new HashSet<>();
//防御式拷贝
Edge<L> newEdge=new Edge<L>(source,target,weight);        	edges.add(newEdge);
//不可修改的视图
return Collections.unmodifiableMap(sourceMap);

三、ADT的应用

1.Poetic Walks

此部分实现明显可分为两个步骤:
第一步是实现图的输入,要注意语料库的内容可能有多行,一行,或空。且上下行元素是相连的,另一个应该注意的地方是若两个元素之间有多个空格,应该也能返回正确结果(个人认为这里有点较真了,但实现也无困难,加之罢了)。关于文件读写有了实验一的经验后也没有困难。需要注意的就是先判断单词是否已经存在,边是否已经存在还有大小写的转换。
关于读入的示例代码如下:

try {
    		while((line=br.readLine())!=null)
    		{
    			int columns_number;
    			String[] Stringword =line.split(" +");
    			columns_number=Stringword.length;
    			ArrayList<String> EveryRow=new ArrayList<String>();
    			for(int j=0;j<columns_number;j++)
    			{
    				EveryRow.add(Stringword[j]);
    			}
    			wordcorpus.add(EveryRow);
    		}
    	}catch (Exception e) {
    		e.printStackTrace();
            System.out.println("file open error");
		}finally {
			br.close();
		}

第二步是实现边的寻找,有了Graph这个ADT之后,实现十分容易。当然这个类的Checkrap,RI,AF,spec也需要填写。

2.FriendshipGraph

完成了上述内容后,此步也无困难,注意点为Person类需要重写equal和Hashcode。而重写equal时侯有许多注意事项,可以按照模板编写,示意如下:
注意Override和Overload的区别,参数必须为Object obj。同时需要先进行对象类型,空的比较判断。这里除了getClass,也可以使用Instanceof,两者区别如下:
java中getClass()方法简介
getClass与instanceof 的区别

@Override
	public boolean equals(Object obj)
	{
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person otherPerson=(Person)obj;
		if(otherPerson.PersonName().equals(this.name))
		{
			return true;
		}
		return false;
	}

四、三次改进

1.可变类型与不可变类型

不可变类型需要我们重写equal与Hashcode。而可变数据类型由于更多基于行为等价性,故我们并不需要重写equal和Hashcode,PPT的例子十分生动阐述了原因。在Vertex类中,如果实现了equal的功能,看似是方便了判断,但由于很多地方使用到了Vertex的集合类,这将导致contain等方法调用时候发生错误!!!
此外,关于重载与重构必须弄清楚,equal中传入的参数必须为Obj obj,而不能是具体的类,这样就变成了overload。

2.测试的改进

在第三周的实验课上,老师修正了我们对测试的误解。正如习题课上所说,对可变数据类型的测试,不仅需要测试变化是否完成,还需要观测变化对其他属性是否有影响。就本问题而言,体现在Set方法的时侯,不仅要判断是否返回正确值,还应该判断是否其他边没有发生变化。获取所有的边可以通过二维Map容器实现,框架示例如下:

private Map<String,Map<String, Integer>> MapreturnEdge(Graph<String> testgraph)
    {
    	Map<String,Map<String, Integer>> a=new HashMap<String,Map<String, Integer>>();
    	for(String testString:testgraph.vertices())
    	{
    		Map<String, Integer> testMap=new HashMap<String, Integer>();
    		testMap=Collections.unmodifiableMap(testgraph.targets(testString));   
    		a.put(testString, testMap);
    	}
    	//结合此函数,在set之后两次获得二维Map判断是否相等。
    	return Collections.unmodifiableMap(a);
    }

3.可复用性的初探

在第三周上课的时候,开始进入最后一部分的学习,引入了LSP原则,值得注意的是,若接口定义抛出异常,而在接口的实现中抛出异常的话相当于是削弱了后置条件,这样并不符合LSP原则。在实验二中,我们的测试策略及实现方法进行了许多的空判断和抛出异常,都是不合格的,需要重新修改。


总结

其他可能对实验有用的链接如下:(实际上便是写文章的时侯忘了当时收藏的原因了哈哈哈)
JUnit assertEquals 两个对象或集合类型
The method assertEquals(Object, Object) is ambiguous for the type Assert解决办法
Java异常被抛出或被捕获之后,代码是否继续执行的问题

这就是实验二的全部总结教训了(写于计算机系统考试周,较为匆忙)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值