一、Coding.Net项目地址:
https://git.coding.net/qiuyuwutong/Operation2.git
URL地址:
二、PSP表格
PSP2.1 |
任务内容 |
计划共完成需要的时间(min) |
实际完成需要的时间(min) |
Planning |
计划 |
30 |
20 |
· Estimate |
· 估计这个任务需要多少时间,并规划大致工作步骤 |
30 |
20 |
Development |
开发 |
960 |
940 |
· Analysis |
· 需求分析 (包括学习新技术) |
30 |
120 |
· Design Spec |
· 生成设计文档 |
30 |
50 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
30 |
20 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
10 |
10 |
· Design |
· 具体设计 |
60 |
60 |
· Coding |
· 具体编码 |
600 |
500 |
· Code Review |
· 代码复审 |
100 |
60 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
100 |
120 |
Reporting |
报告 |
100 |
190 |
· Test Report |
· 测试报告 |
60 |
150 |
· Size Measurement |
· 计算工作量 |
30 |
10 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
10 |
30 |
三、
信息隐藏()指在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是不可访问的。
接口设计( )
耦合性是指模块间互相依赖的程度。松耦合(loose coupling)降低了不同模块间的依赖程度
四、计算模块接口的设计与实现过程
(一)设计Create类
通过调用Create类里面的createExpression方法可以产生满足条件的运算式
(二)设计Calculate类
用来计算运算式的值,其中JS里面的eval()函数
五、计算模块接口部分的性能改进
Create.java
问题一:是否产生括号
设计思路:设计运算优先级,加减运算优先级小于乘除运算优先级,如果相邻两个运算符前面运算符优先级小于后面运算符的优先级,则在前面的运算式加上括号。代码如下:
for(int j=1;j<=sumOfOperation-1;j++){
//System.out.println(bracketExist);
if(bracketExist&&priority(operatorCreate[j-1])<priority(operatorCreate[j])){
ex="("+ex+")"+operatorCreate[j]+String.valueOf(number[j+1]);
}
else{
ex+=operatorCreate[j]+String.valueOf(number[j+1]);
}
if(fractionExist(ex)){
break;
}
}
问题二:实现至少生成两种运算符
设计思路:要满足生成两种不同的运算符,只要让后一个产生的运算符不等于前一个产生的运算符即可。代码如下:
number[0] = random.nextInt(scope_Upper-scope_Lower+1)+scope_Lower;
for (int j = 1; j <= sumOfOperation; j++) {
number[j] = random.nextInt(scope_Upper-scope_Lower+1)+scope_Lower;
while(number[j]==number[j-1])
number[j] = random.nextInt(scope_Upper-scope_Lower+1)+scope_Lower;
// System.out.println(number[j]);
}
问题三:是否产生乘除
设计思路:运算符存放在一个数组char[] operator= new char[]{ '+' , '-' , '*' ,'/' }里,如果不产生乘除,随机产生的运算符范围在数组的前两个元素;如果产生运算符,就让随机产生的运算符 范围在整个数组。代码如下:
for (int j = 0; j < sumOfOperation; j++) {
int op=0;
if(mul_Div)
op = random.nextInt(4);//是否有乘除法
else
op = random.nextInt(2);
operatorCreate[j]=operator[op];
}
问题四:是否在运算过程中产生分数
设计思路:在运算过程中判断是否产生分数,如果产生分数,就让其重新生成运算式。代码如下:
public static boolean fractionExist(String ex)
{
double answer = Double.parseDouble(Calculate.calculateExpression(ex));
if(Math.floor(answer)!=answer||answer<0||answer>9999){
return true;
}else{
return false;
}
}
Command.java
问题一:怎么一次输入多个命令行参数,而且参数的前后顺序并非是固定的
例如 java Command -m 1 50 -n 20 -c
设计思路:通过for循环来遍历命令行参数,通过switch语句来处理每次循环输入的命令行参数。代码如下:
for (int i = 0; i < args.length; i++) {
switch(args[i]){
case "-n"://题目的数量
case "-N":
这里设置两个case "-n",case "-N",来解决大小写不区分这个问题。
性能分析图:
六、计算模块部分单元测试展示
测试输入的参数是否合法时,预期值先给了一个合法值,再给一个非法值,分别进行测试。
Command.Java
//测试输入的参数是否合法
@Test()
public void testParameter1Error1(){
String ex ="-n";
assertEquals(true,new Command().parameter1Error(ex));
}
@Test()
public void testParameter1Error2(){
String ex ="-z";
assertEquals(false,new Command().parameter1Error(ex));
}
//测试输入的参数n是否合法
@Test
public void testScopeOfSumError1(){
int num=-1;
assertEquals(false, new Command().scopeOfSumError(num));
}
@Test
public void testScopeOfSumError2(){
int num=10;
assertEquals(true, new Command().scopeOfSumError(num));
}
(一)parameter1Error函数
作用:判断输入的参数是否是-n,-m等
public static boolean parameter1Error(String ex){
ArrayList<String> args = new ArrayList<String>();
args.add("-n");args.add("-N");
args.add("-m");args.add("-M");
args.add("-o");args.add("-O");
args.add("-c");args.add("-C");
args.add("-b");args.add("-B");
if(args.contains(ex)){
return true;
}
else{
return false;
}
}
(二)scopeOfSumError函数
作用:测试输入的参数-n是否合法。
public static boolean scopeOfSumError(int num){
if(num<=0||num>10000)
return false;
else{
return true;
}
}
CalculateJava
(一)calculateExpression函数
作用:接收的是一个表达式,返回的是表达式的结果,以下是calculateExpression函数:
public static String calculateExpression(String ex){
try {
return String.valueOf(engine.eval(ex));
} catch (ScriptException e) {
e.printStackTrace();
return null;
}
}
以下是calculateExpression函数的单元测试:
@Test
public void test() {
String ex ="3*4-6/2";
assertEquals("9",new Calculate().calculateExpression(ex));
}
测试覆盖率截图:
七、计算模块部分异常处理说明
(一) 判断输入的参数的格式是否正确
比如,用户输入-z,-t等参数,就会提示用户错误。
如下图所示:
测试样例:
(二)判断输入的参数-n、-m的格式是否正确
例如,输入-n t就会报错
如下图所示:
测试样例:
(三)判断参数n、m、o的参数范围是否正确
如下图所示:
测试样例:
八、界面模块的详细设计过程
界面分三个版块,第一个版块为出题,第二个版块为答题,第三个版块为答题结果。支持两种语言,中文与English。用到的前端技术有HTML、CSS、JavaScript、bootstrap。
(一)出题版块:选用bootstrap框架
点击打印题目就跳转到答题板块
(二)答题界面
用js写了计时器计时,答题结束后不归0,便可方便的得知答题所用最终时间。界面如下图所示:
(三)答题结果
显示答对多少题和共答题多少
代码展示:
1.中英文切换:
<select class="selectLanguage" class="form-control" language=javascript onchange= " location.href=this.value">
<option value ="中文">中文</option>
<option value="CalEnglish.html">English</option>
</select>
2.计时器:
HTML代码:
<ul style="position: absolute;bottom: 380px; left: 160px; list-style-type: none">
<input type="button" name="btn" class="btn-lg btn-info" onclick="startclock() " value="开始答题">
<input type="button" name="btn" class="btn-lg btn-info" value="暂停答题" onclick="pauseclock()">
<input type="button" name="btn" class="btn-lg btn-info" onclick="stopclock()" value="停止答题">
<input class="btn" name="showtime" style="color:#ff0000;200px;height: 48px;font-size: 20px;" id="showtime" type="text" value="0时0分0秒">
</ul>
JS代码:
<script language="javascript">
var se,m=0,h=0,s=0,ss=1;
function second(){
if((ss%100)==0){s+=1;ss=1;}
if(s>0 && (s%60)==0){m+=1;s=0;}
if(m>0 && (m%60)==0){h+=1;m=0;}
t=h+"时"+m+"分"+s+"秒"+ss+"毫秒";
document.getElementById("showtime").value=t;
ss+=1;
document.getElementById("one").value=h;
document.getElementById("two").value=m;
document.getElementById("three").value=s;
}
function startclock(){se=setInterval("second()",10);}
function pauseclock(){clearInterval(se);}
function stopclock(){clearInterval(se);ss=1;m=h=s=0;}
</script>
九、界面模块与计算模块的对接
十、描述结对的过程
我们两个刚开始着手做项目的那个下午一起初步完成了计算模块,之前两个人的项目均没有加上括号,一起通过学习加上了括号,但是当时没有解决两个问题。第一:不知如何设定是否有乘除法;第二、不知如何确保一次输入多个参数,而且参数可以任意顺序。最后解决了这个问题。具体解决方案前面有详细说明,这里不再赘述。第一天非常顺利。
第二天计划完成异常处理模块,但是却花费了很长时间完善第一个计算模块,之前大概实现了,但是有一些细节没有考虑到(如参数的大小写问题)。完善计算模块后开始着手做异常模块,但因为两个人对异常都掌握的不太好,花费了很长时间学习自定义异常等等,最终完成了异常模块。整体还算顺利,耗费的时间主要是因为对异常的掌握程度不够。
第三天尝试做单元测试,也比较顺利,但是那时不明白对异常进行单元测试,请教了学姐之后解决了问题。当天,我们完成了前端界面的设计图。
完成了设计图后,敲出了前台界面,本以为一切很顺利了,但是没想到是更难的阶段,前后端交互的时候遇到了很多问题。项目在两个人的电脑上导过来导过去,就报了很多莫名其妙的错误,两个人都重新配了好几次环境。之后花了很多的时间调代码,在完成后两个人一起写了博客,对这次的作业进行了总结。
十一、结对编程优缺点及个人优缺点
(一)结对编程优点
结对编程是两个人的智慧,两个人的思考,看待问题肯定会更全面一些。就例如我们,两个人都没有完成括号,两个人在一起很容易就加上了括号。遇到Bug也没有那么恐惧,自己思考过后总习惯问一句:“**你怎么看呢?”一般这种时候,我们总会想出一个比较完美的解决方案,然后非常非常开心,感觉解决一个Bug比自己纯敲一段代码都要快乐得多。
两个人在一起编程时有时候会避免一些低级错误,有时候可能只是因为字母打错了,就导致工程止步不前,两个人编程,加上眼镜八只眼睛在盯着,避免犯一些低级错误。
我们两个每次一起编程最少在五个小时,一个人的精力是有限的,有时候编着编着就会特别累,这个时候就会换一下位置,让自己的身体和大脑都有个缓冲。
(二)结对编程缺点
有时候对于同一个问题,我们有不同的思考,有时候就会有些分歧。编程习惯也有些不同,可能一个人习惯的编程方式恰好是另一个人最讨厌的方式,不过总归是要磨合的。
(三)个人优缺点
1、颜超一
优点:认真,严谨,考虑全面,耐心,逻辑能力强
缺点:太过于追求细节
2、丁小帅
优点:能吃苦、耐心、热情、思考能力不错
缺点:不注重细节