结对编程
题目描述:
不知道大家是否尝试过这样一种开发模式:你有一个伙伴,你们坐在一起,并肩作战,面对着同一台显示器,使用着同一键盘,同一个鼠标,你们一起思考,一起分析,一起编程?这次,就让我们来体验一下结对编程的魅力:
http://www.cnblogs.com/xinz/archive/2011/08/07/2130332.html
我们在个人作业1中,用各种语言实现了一个命令行的四则运算小程序。进一步,本次要求把这个程序做成GUI(可以是Windows PC 上的,也可以是Mac、Linux,web,手机上的),成为一个有基本功能、一定价值的程序。在下面的功能需求中实现两个:
- 记录用户的对错总数,程序退出再启动的时候,能把以前的对错数量保存并在此基础上增量计算。
- 有计时功能,能显示用户开始答题后的消耗时间。
- 界面支持中文简体/中文繁体/英语,用户可以选择一种;
从题目要求中我们选择了1和2两个功能,即实现记录用户对错题数和计时功能。
码市地址:https://coding.net/u/lzx84/p/Calculation/git
一、队员组成以及分工情况
队员有: 201421123062(林燕) 201421123084(林至贤)
实现记录用户的对错题数由林至贤完成,我(林燕)实现显示用户开始答题后的消耗时间。整体的一起讨论完成。
编程过程使用了QQ的屏幕共享,一个人写的时候,另一个人在观看,并通过语音互相交流想法。
需求分析(新功能):
- 记录用户的对错总数,程序退出再启动的时候,能把以前的对错数量保存并在此基础上增量计算。(使用session存放统计对象列表的方法,一个对象相当于一次操作(感觉应该使用cookie,可是做了好久没法实现))
- 有计时功能,能显示用户开始答题后的消耗时间。(使用js的计时代码,使用获取两次系统时间相见计算用时。(因为JS不怎么熟,不怎么懂得用JS获取具体用时))
- 界面支持中文简体/中文繁体/英语,用户可以选择一种;(未实现)
二、程序设计过程
我们讨论了两个人的第一次四则运算的代码,考虑到我之前的代码没有很好地封装对象,便决定用至贤的第一次成果来做基础,在他之前的基础上改进,增加了一个新的对象,以便于后面的统计。我们用了jsp来写页面,一共设计了四个页面,具体看图:
新增类:
流程:
三、核心代码展示
index.jsp:
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=UTF-8"%> 3 <html> 4 5 <head> 6 <meta http-equiv="Content-Language" content="zh-cn"> 7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 8 <title>提交</title> 9 </head> 10 11 <body 12 style="background-image: url('images/background.jpg');background-position: center;"> 13 <p></p> 14 <p align="center"> 15 <font face="华文彩云" size="7">四则运算器</font> 16 </p> 17 <form method="POST" action="show.jsp"> 18 <p align="center"> 19 请输入需要的题目数量:<input name="n" type="text" onkeyup="this.value=this.value.replace(/\D/g,'')" 20 onafterpaste="this.value=this.value.replace(/\D/g,'')" /> <!--规定用户只能输入数字--> 21 22 <input type="submit" value="确认" 23 name="B1"> 24 </p> 25 26 </form> 27 <P align="center"><a href="showHistory.jsp">查看历史成绩</a></P> 28 29 30 31 32 </body> 33 34 </html>
show.jsp:
1 <%@page import="model.*" import="methods.*"%> 2 <%@page language="java" import="java.util.*" 3 contentType="text/html; charset=UTF-8"%> 4 <% 5 String path = request.getContextPath(); 6 String basePath = request.getScheme() + "://" 7 + request.getServerName() + ":" + request.getServerPort() 8 + path + "/"; 9 %> 10 11 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 12 <html> 13 <head> 14 <base href="<%=basePath%>"> 15 16 <title>My JSP 'show.jsp' starting page</title> 17 18 <meta http-equiv="pragma" content="no-cache"> 19 <meta http-equiv="cache-control" content="no-cache"> 20 <meta http-equiv="expires" content="0"> 21 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 22 <meta http-equiv="description" content="This is my page"> 23 <!-- 24 <link rel="stylesheet" type="text/css" href="styles.css"> 25 --> 26 27 </head> 28 29 <body> 30 <div align="center" > 31 <form method="POST" action="showResult.jsp"><% 32 33 int op = 0; 34 int n = Integer.parseInt(request.getParameter("n")); 35 ArrayList<Fraction> resultlist = new ArrayList<Fraction>();//创建结果列表,存放答案 36 ArrayList<String> titlelist = new ArrayList<String>();//创建题目列表,存放题目 37 String title = ""; 38 for (int i = 1; i <= n; i++) { 39 Fraction f1 = Dofrac.CreatFrac(); 40 Fraction f2 = Dofrac.CreatFrac(); 41 op = (int) (Math.random() * 4 + 1); 42 Fraction result = new Fraction(); 43 %><div> 44 <p> 45 <% 46 switch (op) { 47 case 1: { 48 result = Calculate.add(f1, f2); 49 title = "第" + i + "题:" + f1.toString() + "+" 50 + f2.toString() + "="; 51 out.println(title); 52 break; 53 54 } 55 case 2: { 56 if (!Calculate.compare(f1, f2)) { 57 Fraction temp = f1; 58 f1 = f2; 59 f2 = temp; 60 } 61 result = Calculate.sub(f1, f2); 62 title = "第" + i + "题:" + f1.toString() + "-" 63 + f2.toString() + "="; 64 out.println(title); 65 break; 66 } 67 case 3: { 68 result = Calculate.mul(f1, f2); 69 title = "第" + i + "题:" + f1.toString() + "*" 70 + f2.toString() + "="; 71 out.println(title); 72 break; 73 } 74 case 4: { 75 if (f2.getFenzi() == 0) { 76 f2.setFenzi((int) (1 + Math.random() * (10 - 1 + 1))); 77 } 78 result = Calculate.div(f1, f2); 79 title = "第" + i + "题:" + f1.toString() + "÷" 80 + f2.toString() + "="; 81 out.println(title); 82 break; 83 } 84 } 85 resultlist.add(result); 86 titlelist.add(title); 87 88 89 90 91 %> 92 <input type="text" name="s<%out.print(i);%>" size="20" 93 style="width: 38px;"> 94 <input type="hidden" name="time" value=<%=System.currentTimeMillis() %> 95 style="width: 38px;"><!--获得系统时间--> 96 97 98 </p> 99 100 </div> 101 <% 102 } 103 %> 104 <input type="submit" value="提交"> 105 </form> 106 </div> 107 <% 108 session.setAttribute("n", n); 109 session.setAttribute("resultlist", resultlist); 110 session.setAttribute("titlelist", titlelist); 111 //将用户输入的n值,结果列表与题目列表存入session 112 %> 113 <div align="center" id="showTimes"></div> 114 <% 115 long current_time = 0; 116 %> 117 <script> 118 var second = 119 <%=current_time / 1000%> 120 ; //秒数 121 122 // 写一个方法,将秒数转换为分钟以及小时 123 var toMinites = function() { 124 var s = second % 60; 125 var mi = (second - s) / 60 % 60; // 分钟 126 var h = ((second - s) / 60 - mi) / 60 % 24; // 小时 127 return h + ":" + mi + ":" + s; 128 } 129 function getTime() { 130 return toMinites; 131 } 132 133 //计时器 134 window.setInterval(function() { 135 second++; 136 document.getElementById("showTimes").innerHTML = toMinites(); 137 }, 1000); 138 </script> 139 </body> 140 </html>
showResult.jsp:
<%@page import="org.apache.taglibs.standard.tag.common.core.ForEachSupport"%> <%@page import="model.*" import="methods.*"%> <%@page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'show2.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <% long nowTime = System.currentTimeMillis();//得到用户做完题目之后的时间 ArrayList<Fraction> resultlist = (ArrayList<Fraction>) session.getAttribute("resultlist"); int n = (Integer) session.getAttribute("n"); ArrayList<String> titlelist = (ArrayList<String>) session.getAttribute("titlelist"); //从session中得到需要的数据 String input; int flag=0;//错题数 String time=(nowTime-Long.parseLong(request.getParameter("time")))/1000+"秒";//将两个时间相减,得到用时 Fraction result = new Fraction(); ArrayList<String> wrongList = new ArrayList<String>();//新建错题集 Statistics st = new Statistics(); for (int i = 1; i <= n; i++) { %> <p> <% out.print(titlelist.get(i - 1)); input = (String) request.getParameter("s" + i); if (Dofrac.check(input)) { out.print(" (你的答案是:" + input+")"); } else { out.print("(非法输入,答案作废)"); } result = resultlist.get(i - 1); if (input.equals(result.toString())) { out.print("————恭喜你!回答正确"); } else { out.print("————回答错误,正确答案是:" + result.toString()); flag++; wrongList.add(titlelist.get(i - 1)); } } %> </p> <hr> <p> <% String acciracy=(n-flag+0.0)/n*100+"%";//计算正确率 out.print("你作对了"+(n-flag)+"题,做错了"+flag+"题,正确率为:"+acciracy+",用时为:"+time); st.setAcciracy(acciracy); st.setTime(time); st.setWrongNum(flag); st.setWrongTitle(wrongList); ArrayList<Statistics> stList =((ArrayList<Statistics>)session.getAttribute("stList")==null)?new ArrayList<Statistics>():(ArrayList<Statistics>)session.getAttribute("stList"); stList.add(st); session.setAttribute("stList", stList); //新建或从session中取得Statistic列表,将此次计算的statistics对象存入。(感觉这里用cookie更合适,不过不会用。。) %> </p> <a href="index.jsp">再做一次</a> </body> </html>
showHistory.jsp
1 <%@page import="model.*" import="methods.*"%> 2 <%@page language="java" import="java.util.*" 3 contentType="text/html; charset=UTF-8"%> 4 <% 5 String path = request.getContextPath(); 6 String basePath = request.getScheme() + "://" 7 + request.getServerName() + ":" + request.getServerPort() 8 + path + "/"; 9 %> 10 11 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 12 <html> 13 <head> 14 <base href="<%=basePath%>"> 15 16 <title>My JSP 'show3.jsp' starting page</title> 17 18 <meta http-equiv="pragma" content="no-cache"> 19 <meta http-equiv="cache-control" content="no-cache"> 20 <meta http-equiv="expires" content="0"> 21 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 22 <meta http-equiv="description" content="This is my page"> 23 <!-- 24 <link rel="stylesheet" type="text/css" href="styles.css"> 25 --> 26 27 </head> 28 29 <body> 30 31 <input type="button" value="返回上一级" onclick="javascript:history.back();"> 32 <br> 33 <br> 34 <div align="center"> 35 <% 36 ArrayList<Statistics> stList = (ArrayList<Statistics>) session 37 .getAttribute("stList");//获取session中的statistics列表。遍历输出。 38 if (stList == null) { 39 out.print("没有记录"); 40 } else { 41 for (int i = 0; i < stList.size(); i++) { 42 %> 43 <div> 44 <% 45 out.print("第"+(i+1)+"次做题:"); 46 47 %><br> 48 <% 49 out.print("---------------------------------------------------"); 50 51 %><br> 52 53 <% 54 out.print("错题数:" + stList.get(i).getWrongNum()); 55 %><br> 56 <% 57 out.print("用时:" + stList.get(i).getTime()); 58 %><br> 59 <% 60 out.print("正确率:" + stList.get(i).getAcciracy()); 61 %><br> 62 <% 63 out.print("错题:"); 64 %><br> 65 <% 66 for (int j = 0; j < stList.get(i).getWrongTitle().size(); j++) { 67 out.print(stList.get(i).getWrongTitle().get(j)); 68 %><br> 69 <% 70 } 71 %><br> 72 <% 73 out.print("---------------------------------------------------"); 74 75 %><br> 76 </div> 77 78 <% 79 } 80 } 81 %> 82 </div> 83 </body> 84 </html>
四、程序展示
做题演示:
功能一(存取用户做题数据)演示:
PSP:
PSP2.1 |
Personal Software Process Stages |
Estimated Time (h) |
RealTime(h) |
Planning |
计划 |
|
|
· Estimate |
估计这个任务需要多少时间 |
|
|
Development |
开发 |
8 |
9 |
· Analysis |
需求分析 (包括学习新技术) |
1 |
2 |
· Design Spec |
生成设计文档 |
0.5 |
0.5 |
· Design Review |
设计复审 |
0.5 |
0.5 |
· Coding Standard |
代码规范 |
1 |
0.5 |
· Design |
具体设计 |
2 |
2.5 |
· Coding |
具体编码 |
2 |
2 |
· Code Review |
代码复审 |
0.5 |
0.5 |
· Test |
测试(自我测试,修改代码,提交修改) |
0.5 |
0.5 |
Reporting |
报告 |
0.5 |
0.5 |
· |
测试报告 |
|
|
· |
计算工作量 |
|
|
· |
并提出过程改进计划 |
|
五、小结感受
1、结对感受
- 这次结对编程合作的还不错,因为之前课程设计已经合作过一次,不懂的东西一起讨论解决,配合的还可以。刚开始实现界面的时候,首先讨论的是用NetBeans还是Web,由于之前的java以及数据库可设都有涉及到jsp,所以便一致认为用jsp来写。接下来就是整体架构的问题了,讨论了是否用servlet以及整个存储结构用什么等。随后便开始了具体的编程,过程中我发现自己的编程能力和学习新技能的能力都想对比较弱,能感受到队友的力量比较强大,1+1还是大于2的,有的时候一个小错误,还有想的不周到之处可以由队友发现,假如没有队友就可能要花费很多时间和精力来处理。
- 结对编程的过程中我更像驾驶员,由于编程基础比较弱,总是有着这样或者那样的小错误;至贤充当着领航员的角色,把握整体架构,饥饿的时候给我一块面包,走错方向了及时互相拉回来。感谢队友辛苦地指导我,让我体会到结对编程的力量,两个人刚开始的时候也有着这样活着那样的不同想法,就命名来说,我就是要驼峰式的命名方式,但是他可能没那么大要求,觉得那样麻烦,但最终慢慢磨合也得到了一致的结果。
- 不论是团队还是结对,听取队友的意见非常重要,我们要学会如何与他人合作,避免一意孤行或者整个过程都不提任何想法。
2、过程中遇到的困难
在编程过程中遇到的问题都是先百度的,有时候一个小问题要解决很久,比如在用git Import项目到eclipse里面的时候遇到了问题,百度了挺久,参考了下面两篇文章:http://blog.csdn.net/dongchengrong/article/details/56833173
http://blog.csdn.net/hil2000/article/details/8566456
在做动态显示计时的功能时没多大想法,百度了一下用window.setInterval();调用了计时器。过程中出现了时间显示上的乱码,最后问了一些人才解决。
下次要提高查找问题答案的速度,提高动手能力。