作业所属班级 | 软件工程4班 |
---|---|
作业的要求 | 结对编程 |
我理解的作业目标 | 实践结对编程的流程 |
本项目由:张永祥(学号3122004546),黄俊杰(学号3122004525)
项目的GitHub链接如下:
TimeP1ayer/SimpleArithmeticProgram: 自动生成小学四则运算题目的命令行程序 (github.com)
PSP | Persional Software Process Stages | 预计耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 5 |
- Estimate | - 估计这个任务需要多少时间 | 10 | 5 |
Development | 开发 | 920 | 915 |
- Analysis | - 需求分析 | 10 | 5 |
- Design Spec | - 生成设计文档 | 100 | 60 |
- Design Review | - 设计复审(和同事审核设计文档) | 20 | 15 |
- Coding Standard | - 代码规范(为目前的开发指定合适的规范) | 10 | 10 |
- Design | - 具体设计 | 300 | 360 |
- Coding | - 具体编码 | 400 | 360 |
- Code Review | - 代码复审 | 20 | 30 |
- Test | - 测试(自测、修改代码、提交修改) | 60 | 75 |
Reporting | 报告 | 40 | 30 |
- Test Report | - 测试报告 | 20 | 10 |
- Size Measurement | - 计算工作量 | 10 | 10 |
- Postmortem & Process Improvment Plan | - 事后总结,并提出过程改进计划 | 10 | 10 |
总时间 | 930 | 920 |
需求分析
本此需求分析在题目里已经有了明确的说明,已经详细到不能再详细了。
生成设计文档
这一次将系统设计成三个模块:
- 解释命令行参数模块:负责将接收到的命令行参数转化成实际程序可用的参数,并且会告诉使用该模块的人,什么功能由于收集到足够的参数,因而可以正常运转。
- 随机表达式生成模块:给它要生成的题目数
n
和数值的范围r
,它就能给你生成一个Map
,这里的键Key
是表达式,Value
是表达式对应的答案。 - 输出和读取模块:负责在选择生成表达式功能时,将表达式和对应的结果按某种方式输出到
Exercises.txt
和Answers.txt
中。
具体设计
解释命令行参数模块
对于参数-n,-r,采用正则表达式来判断其后面的参数是否为纯数字。
对于参数-e,-a,采用判断文件路径是否存在的方式来防止出现读取错误。
实现方式比较简单。
随机表达式生成模块
因为解释起来太长了,于是写了另外一篇博客,用来解释我们随机表达式生成模块的运行。
关于四则运算的一些想法 - onezhan - 博客园 (cnblogs.com)
输入输出模块
答案的读取:
文本读取采用UTF_8格式。
采用正则表达式读取作答的答案与原题目答案进行对比,将结果输出到一个ArrayList里,再交由其他模块进行结果的写入。
写入文件时均采用覆写方式。
单元测试(使用JUnit4)
我们为每一个单元尽最大努力模拟了用户可能的输入
命令行解释模块
public class CommandUtilTest {
@Test
public void getParameter() {
CommandUtil c = new CommandUtil();
//正常输入参数
String args[] = { "-r","70" , "-n","80" ,"-a","-el","-e","-xp"};
c.getParameter(args);
System.out.println("A:"+c.getA());
System.out.println("E:"+c.getE());
System.out.println("R:"+c.getR());
System.out.println("N:"+c.getN());
System.out.println("-----------");
//缺少不必要参数
CommandUtil c1 = new CommandUtil();
String args1[] = {"-n","80","-r","70","-e","-xp"};
c1.getParameter(args1);
System.out.println("A:"+c1.getA());
System.out.println("E:"+c1.getE());
System.out.println("R:"+c1.getR());
System.out.println("N:"+c1.getN());
System.out.println("-----------");
//缺少必要参数
CommandUtil c2 = new CommandUtil();
String args2[] = {"-n","80","-e","-xp"};
c2.getParameter(args2);
System.out.println("A:"+c2.getA());
System.out.println("E:"+c2.getE());
System.out.println("R:"+c2.getR());
System.out.println("N:"+c2.getN());
System.out.println("-----------");
//参数缺少
CommandUtil c4 = new CommandUtil();
String args4[] = { "-r", "-n" , "-a","D:\\Users\\Desktop\\exp.txt" , "-e","-xp" };
c4.getParameter(args4);
System.out.println("A:"+c4.getA());
System.out.println("E:"+c4.getE());
System.out.println("R:"+c4.getR());
System.out.println("N:"+c4.getN());
System.out.println("-----------");
}
}
随机表达式生成模块
public class RandomExpressionTest {
@Test
public void ToStringTest() {
// 测试整数
Fraction f1 = new Fraction(2, 1);
System.out.println(f1.ToString());
// 测试真分数
Fraction f2 = new Fraction(1, 6);
System.out.println(f2.ToString());
// 测试假分数
Fraction f3 = new Fraction(16, 6);
System.out.println(f3.ToString());
// 分子和分母相等
Fraction f4 = new Fraction(3, 3);
System.out.println(f4.ToString());
// 测试负数
Fraction f5 = new Fraction(-1, 3);
System.out.println(f5.ToString());
Fraction f6 = new Fraction(1, -3);
System.out.println(f6.ToString());
Fraction f7 = new Fraction(3, -2);
System.out.println(f7.ToString());
// 测试分母为零
try {
Fraction zero = new Fraction(1, 0);
}
catch (Exception e) {
System.out.println(e.toString());
}
// 对分数加法的测试
// 正数的加法
Fraction a1 = new Fraction(2, 1);
Fraction a2 = new Fraction(1, 4);
System.out.println(a1.Add(a2).ToString());
// 存在负数的加减法
a1 = new Fraction(-1, 2);
a2 = new Fraction(2, 1);
System.out.println(a1.Add(a2).ToString());
// 对分数的减法测试
a1 = new Fraction(1, 4);
a2 = new Fraction(2, 1);
System.out.println(a1.Sub(a2).ToString());
System.out.println(a2.Sub(a1).ToString());
// 对分数的乘法进行测试
a1 = new Fraction(3, 4);
a2 = new Fraction(-4, 3);
System.out.println(a1.Mul(a2).ToString());
a2 = new Fraction(4, 3);
System.out.println(a1.Mul(a2).ToString());
// 对分数的除法进行测试
a1 = new Fraction(3, 4);
a2 = new Fraction(2, 5);
System.out.println(a1.Div(a2).ToString());
a1 = new Fraction(2, -5);
System.out.println(a1.Div(a2).ToString());
}
@Test
public void CreateExpressionTest() {
CreateExpression a = new CreateExpression(30, 2);
Map<String, String> tmp = a.getExpressionAndResult();
for(String exp : tmp.keySet()) {
System.out.println(exp);
}
}
}
输入输出模块
public class ReadUtilTest {
@Test
public void countLine() {
System.out.println("line:"+ ReadUtil.CountLine("D:\\Users\\Desktop\\exp.txt"));
}
@Test
public void getResult() {
System.out.println(ReadUtil.GetResult("D:\\Users\\Desktop\\exp.txt",3,"."));
System.out.println(ReadUtil.GetResult("D:\\Users\\Desktop\\exp.txt",5,"="));
}
@Test
public void ResultCompare(){
ArrayList<Integer>[] GetCompareResult = ReadUtil.ResultCompare("D:\\Users\\Desktop\\result.txt","D:\\Users\\Desktop\\result2.txt");
ArrayList<Integer>Correct = GetCompareResult[0];
ArrayList<Integer>Wrong = GetCompareResult[1];
System.out.print("Correct:");
for (int num:Correct){
System.out.print(num+" ");
}
System.out.println();
System.out.print("Wrong:");
for(int n:Wrong){
System.out.print(n+" ");
}
}
@Test
public void writeExpression() {
CreateExpression a = new CreateExpression(10,10);
Map<String, String> tmp = a.getExpressionAndResult();
WriteUtil.WriteExpression(tmp,"D:\\Users\\Desktop\\exp.txt","D:\\Users\\Desktop\\result.txt");
}
@Test
public void CompareResult(){
WriteUtil.WriteCompareResult(ReadUtil.ResultCompare("D:\\Users\\Desktop\\result.txt","D:\\Users\\Desktop\\result2.txt"),"D:\\Users\\Desktop\\Compareresult.txt");
}
}
性能测试
给了这么一串参数,性能测试的结果如下:
String[] args0 = {"-n", "100000000", "-r", "1000"};
耗费最多的就是 Fraction
,Expression
及其子类,这是生成大量表达式以及查重模块所带来的代价。当生成的题目数量越多时,Expression
生成的表达式树就会越多,为了进行查重,存起来的表达式树就会越来越多,因此当数据规模足够大时,该算法对内存的消耗量也是非常大的。
但考虑到我们只要求一万道题目的数量,而我们所做测试是一千万道题目的数量,所以可以想象大概是本次性能测试的所有资源消耗量,都几乎会下降一千倍,那这样的性能消耗,对于我们来说就是可以接受的。
总结
张永祥
对本次项目进行总结:
(1)项目的成功之处:
-
高效沟通:在结对编程中,我们保持了高效的沟通,及时解决了编程过程中遇到的问题。
-
互相学习:通过互相监督,我们互相学习了对方的编程技巧和思维方式,提高了自身的编程水平
(2)不足之处:
- 没有足够严格地按照结对编程的方法解决问题
- 因为前期没有定义好相关规范、任务,导致开发过程中有种撕裂感,有种在完成单人项目的感觉。
(3)经验分享
- 在团队中,合理的系统设计文档,能有效组织人员进行开发,让每个人的能力得到充分利用。
黄俊杰
对本次项目进行总结:
(1)项目的成功之处:
- 高效沟通:在结对编程中,我们保持了高效的沟通,及时解决了编程过程中遇到的问题。
- 互相学习:通过互相监督,我们互相学习了对方的编程技巧和思维方式,提高了自身的编程水平
- 使用新方式:第一次使用git进行多人项目的管理,代码版本管理良好
(2)不足之处:
- 没有足够严格地按照结对编程的方法解决问题
- 对git的使用方法不熟练,个人代码版本更新有可能因为交流滞后,造成代码冲突,在提交和merge时出现问题
- 我比较像摸鱼,对算法设计基本没有贡献