Github的仓库主页链接地址:https://github.com/Opalus-wangs/Pair-Programming
一、需求分析
任务1:
在《实验二 软件工程个人项目》中,同学们实现了一个命令行四则运算出题小程序,本次实验采用结对编程方式,设计开发一个小学生四则运算练习软件,使之具有以下功能:
(1)由计算机从题库文件中随机选择20道加减乘除混合算式,用户输入算式答案,程序检查答案是否正确,每道题正确计5分,错误不计分,20道题测试结束后给出测试总分;
(2)题库文件可采用实验二的方式自动生成,也可以手工编辑生成,文本格式如下:
(3)程序为用户提供三种进阶四则运算练习功能选择:百以内整数算式(必做)、带括号算式、真分数算式练习;
(4)程序允许用户进行多轮测试,提供用户多轮测试分数柱状图,示例如下:
(5)程序记录用户答题结果,当程序退出再启动的时候,可为用户显示最后一次测试的结果,并询问用户可否进行新一轮的测试;
(6)测试有计时功能,测试时动态显示用户开始答题后的消耗时间。
(7)程序人机交互界面是GUI界面(WEB页面、APP页面都可),界面支持中文简体(必做)/中文繁体/英语,用户可以进行语种选择。
二、软件设计
1.流程图
2.类图
三、核心代码
计时部分:
import java.util.Timer; import java.util.TimerTask; public class time { public Timer timer=new Timer(); public boolean is_pause=false; public timetask mytimetask=new timetask(); public int hh,mm,ss; String a; public time() { timer.scheduleAtFixedRate(mytimetask, 0, 1000); } public class timetask extends TimerTask{ public int count_time=0; public String date; @Override public void run() { if(!is_pause) { count_time++; hh=count_time/3600; mm=(count_time%3600)/60; ss=count_time%60; date=hh+":"+mm+":"+ss; a=date; } } } }
结果计算:
//表达式计算 import java.math.BigDecimal; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Calculate { public static int arithmetic(String exp) { String result = parseExp(exp).replaceAll("[\[\]]", ""); return (int)Double.parseDouble(result); } public static String parseExp(String expression) { expression=expression.replaceAll("\s+", "").replaceAll("^\((.+)\)$", "$1"); String checkExp="\d"; String minExp="^((\d+(\.\d+)?)|(\[\-\d+(\.\d+)?\]))[\+\-\*\/]((\d+(\.\d+)?)|(\[\-\d+(\.\d+)?\]))$"; //最小表达式计算 if(expression.matches(minExp)) { String result=calculate(expression); return Double.parseDouble(result)>=0?result:"["+result+"]"; } //计算不带括号的四则运算 String noParentheses="^[^\(\)]+$"; String priorOperatorExp="(((\d+(\.\d+)?)|(\[\-\d+(\.\d+)?\]))[\*\/]((\d+(\.\d+)?)|(\[\-\d+(\.\d+)?\])))"; String operatorExp="(((\d+(\.\d+)?)|(\[\-\d+(\.\d+)?\]))[\+\-]((\d+(\.\d+)?)|(\[\-\d+(\.\d+)?\])))"; if(expression.matches(noParentheses)) { Pattern patt=Pattern.compile(priorOperatorExp); Matcher mat=patt.matcher(expression); if(mat.find()) { String tempMinExp=mat.group(); expression=expression.replaceFirst(priorOperatorExp, parseExp(tempMinExp)); } else { patt=Pattern.compile(operatorExp); mat=patt.matcher(expression); if(mat.find()) { String tempMinExp=mat.group(); expression=expression.replaceFirst(operatorExp, parseExp(tempMinExp)); } } return parseExp(expression); } //计算带括号的四则运算 String minParentheses="\([^\(\)]+\)"; Pattern patt=Pattern.compile(minParentheses); Matcher mat=patt.matcher(expression); if(mat.find()) { String tempMinExp=mat.group(); expression=expression.replaceFirst(minParentheses, parseExp(tempMinExp)); } return parseExp(expression); } public static String calculate(String exp) { exp=exp.replaceAll("[\[\]]", ""); String number[]=exp.replaceFirst("(\d)[\+\-\*\/]", "$1,").split(","); BigDecimal number1=new BigDecimal(number[0]); BigDecimal number2=new BigDecimal(number[1]); BigDecimal result=null; String operator=exp.replaceFirst("^.*\d([\+\-\*\/]).+$", "$1"); if("+".equals(operator)) { result=number1.add(number2); } else if("-".equals(operator)) { result=number1.subtract(number2); } else if("*".equals(operator)) { result=number1.multiply(number2); } else if("/".equals(operator)) { result=number1.divide(number2,2, BigDecimal.ROUND_HALF_EVEN); } return result!=null?result.toString():null; } }
柱状图:
import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.util.ArrayList; import java.util.Random; import javax.swing.JFormattedTextField; import javax.swing.JFrame; import javax.swing.JTextArea; //绘制柱状图 public class Picture extends JFormattedTextField { int [] a=new int[20]; int j=0; int i=0; int x=0; int aa=0; //绘制柱形统计图 private Random ran; public Picture(ArrayList<Student> students) { super(); for(Student e: students ) { a[j]=(e.getw()); j++; } ran = new Random(); setName("绘制柱形图"); setBounds(100,85,270,210); } @Override public void paint(Graphics g){ int Width = getWidth(); int Height = getHeight(); int leftMargin = 2;//柱形图左边界 int topMargin = 5;//柱形图上边界 Graphics2D g2 = (Graphics2D) g; int ruler = Height-topMargin-5; int rulerStep = ruler/10;//将当前的高度评分为10个单位 g2.setColor(Color.WHITE);//绘制白色背景 g2.fillRect(0, 0, Width, Height);//绘制矩形图 g2.setColor(Color.LIGHT_GRAY); for(int i=0;i<=10;i++){//绘制灰色横线和百分比 g2.drawString((100-10*i)+"%", 5, topMargin+rulerStep*i);//写下百分比 g2.drawLine(5, topMargin+rulerStep*i, Width, topMargin+rulerStep*i);//绘制灰色横线 } g2.setColor(Color.RED); for(i=0;i<j;i++){//绘制柱形图 int value =(20-a[i])*10+5; int step = (i+1)*20;//设置每隔柱形图的水平间隔为40 //绘制矩形 g2.fillRoundRect(leftMargin+step*2, Height-value, 20, value, 20, 20); g2.drawString("C"+(i+1)+"-"+(20-a[i])*5+"%", leftMargin+step*2, Height-value-5); } } }
四、程序运行
1.首先是主界面:
2.点击简单后,出现用户登录的界面,用户登录完成后,点击确定:
3.出现做题界面:
4.点击开始计时时,并开始做题:
5.如果我们没有答完题,提交的时候才能提示信息:
6.做完点击提交,出现成绩和错误题号,并且画出柱状图:
7.点击继续,选择复杂计算:
8.显示结果:
9.点击查看:
五、结对编程过程
六、PSP
PSP2.1 | 任务内容 | 计划完成的时间(min) | 实际完成需要的时间(min) |
---|---|---|---|
PLanning | 计划 | 60 | 80 |
Estimate | 估计这个任务需要多少时间,并规划大致工作步骤 | 60 | 80 |
Developmet | 开发 | 450 | 520 |
Analysis | 需求分析(包括学习新技术) | 30 | 40 |
Design Spec | 生成设计文档 | 10 | 20 |
Design Revie | 设计复审(和同事审核设计文档) | 30 | 30 |
Coding Standard | 代码规范 | 30 | 30 |
Design | 具体设计 | 60 | 60 |
Coding | 具体编码 | 240 | 290 |
Code Review | 代码复审 | 30 | 30 |
Test | 测试(自我测试,修改代码,提交修改) | 20 | 20 |
Reporting | 报告 | 40 | 40 |
Test Report | 测试报告 | 20 | 20 |
Size Measurement | 计算工作量 | 5 | 5 |
Postmortem & Process Improvement Plan | 事后总结,并提出过程改机计划 | 15 | 15 |
七、对小伙伴的评价
对于我的partner,我想说一声谢谢。在本次结对编程中,我们并不是一帆风顺,遇到了很多的困难,但我们都没有选择放弃,而是在互相鼓励中,成功完成了实验。我的partner她是一个动手能力很强,且有自己独特想法的同学,在实验过程中,以其熟练的编程能力,删掉了我冗余代码,使得程序的结构更加清楚明了,代码也更加的规范,这一点值得我去学习,还有一点就是对待事情认真的态度,例如在每添加一个控件的时候,都极力的使其对称整体,可以说是一丝不苟。总的来说,这次的结对编程很快乐,在不知不觉中就完成了实验,没有往日做实验的枯燥,相反,更愿意讨论彼此对问题的想法。这也增加我们解决问题的信心和动力。谢谢我们都不曾放弃无所畏惧自己。
八、 结对编程真的能够带来1+1>2的效果吗?通过这次结对编程,请谈谈你的感受和体会。
通过本次结对编程,我觉得是结对编程1+1>2的,因为在实验过程中,我确切的感受到了合作的重要性,当一个人的想法不正确的时候,你的同伴可以很快的提醒你,两个人一起讨论问题,可以更快的解决问题,可以有很多新的想法产生。而且当你遇到困难的时候,你也不会轻易的放弃,因为你的同伴还在努力尝试着。两个人一起编程,你感觉不到编程的枯燥与乏味,反而是很轻松,很愉快,很享受彼此讨论自己想法的过程。