作业源代码地址:https://git.coding.net/mal123/arithmetic.git

网页版测试地址:http://47.93.197.5:8080/mal_war_exploded/arithmetic?state=toHome

结对成员:马玲 2016012054 ;王雪 2016012013

1.开始实现程序之前,我们对程序的各个模块开发上耗费时间的估计如下PSP所示表格:

PSP

任务内容

计划时间(min)

Planning

计划

60

Estimate

估计这个任务需要多少时间,并规划大致工作步骤

30

Development

开发

1200

Test

测试

90

Algorithm Optimization

算法优化

180

Interface Design

接口设计

150

Coding Standard

代码规范

240

Design

具体设计

120

Coding

具体编码

450

Code Review

代码复审

90

Test

测试

60

Reporting

报告

180

Test Report

测试报告

120

Size Measurement

计算工作量

30

Postmortem & Process Improvement Plan

事后总结, 并提出过程改进计划

120

2.关于Information Hiding, Interface Design, Loose Coupling在项目中的应用:

  1.)Information Hiding:信息隐藏。

信息隐藏是程序设计过程中的一种隔离原则,可以防止用户接触到一个类的某些部分。一个程序模块可以将它的信息隐藏起来,对外仅仅展现出一种接口。当这个模块的具体实现发生改变时,只要保证它的接口不发生变化,则就算不修改模块外的其他代码,程序依旧可以正确执行。对于面向对象的程序设计而言,信息隐藏是一种重要的软件开发手段,它与对象的封装(encapsulation)和模块化(modularity)密切相关,每个模块完成一个特定的子功能,所有的模块按某种方法组装起来,成为一个整体,完成整个系统所要求的功能。主要是封装完成之后,后面做项目用起来会很轻松,并且节约工作量和时间,减少错误以及避免代码的臃肿影响代码的可读性。

在这次的结对项目中,对于用户而言,只需要设置自己的参数,得到相应的题目,用户并不关心程序是怎么生成题目的,他只是调用这个方法,所以可以将生成题目这一模块设计成接口,计算这一模块也是同样的道理。在模块的优化过程中,保证接口不变,我们只需要修改接口的实现,并不需要对其他地方进行修改,程序也可以正常运行。

2.)Interface Design:接口设计。

关于接口的设计,我们也阅读了一些资料,其中有一篇我觉得很有用:https://www.jianshu.com/p/580b943d68e2在设计接口的过程中,不仅要解决当前问题还有保证程序的可扩展性,命名要做到见名知意。对于本次项目来说,我们采用的是mvc模式开发,所以在不同的层都会用到设计的接口,所以命名一定要规范,能够让队友清楚地理解每一个方法所实现的功能,若涉及到多人的项目中,则更应该写一个详细的接口文档来说明。

3.)Interface Design:松耦合。

接口的设计要满足的一个原则就是松耦合,松耦合的接口设计使得程序设计的可拓展性大大增强。新设计的类通过实现某个接口,可以轻轻松松地替换当前的某个类,而无需修改调用这些接口的类。所以我们在设计过程中要尽可能减少模块之间的依赖,达到松耦合。

3.计算模块接口的设计与实现过程

  对于本次的项目,我们会设计两个接口分别实现生成题目和计算题目的功能。具体设计见下图:

生成题目模块的接口:

结对作业(web)-LMLPHP

结对作业(web)-LMLPHP

  各个方法之间的关系:

结对作业(web)-LMLPHP

  计算题目模块的接口:

结对作业(web)-LMLPHP

  本次项目开发,我们采用的是我之前个人项目的代码,我们将之前生成题目和计算的功能分开,仍旧采用之前的算法生成题目,所以具体流程图就不再多做展示了。在之前算法的基础上加入上下界的限制,以及选择乘除法和括号的功能,具体代码写在接口的实现里。在业务逻辑层,获取用户的请求,调用对应的接口,做出响应。由于此次项目要求只需要生成符合要求的题目并不要求算出答案,计算也是对已有的题目直接进行计算,所以在计算题目这一功能的实现我们采用的是eval()函数,直接用于计算用户上传的题目。

4. 计算模块接口部分的性能改进

  我们用JProFiler对内存、ALL OBJECT、Record Object等方面进行了分析:

项目总体分析图:

结对作业(web)-LMLPHP

CPU分析图:

结对作业(web)-LMLPHP

性能分析:

结对作业(web)-LMLPHP

结对作业(web)-LMLPHP

结对作业(web)-LMLPHP

结对作业(web)-LMLPHP

结对作业(web)-LMLPHP

  在项目中消耗最大的函数isParenthesis方法,由于限制条件太多,所以当题目数量过大时,函数消耗会很大。在分析过程中发现在运行过程中,没有对循环时产生的list清空,所以浪费很大空间,针对这些问题,我们也对代码进行了修改。

5.计算模块部分单元测试展示

  在单元测试中,我们首先对两个接口的基本功能进行了测试,在确保基本功能都可以正确实现之后,我们对Command类进行了单元测试。

  Command类测试代码如下:

 import org.junit.Test;

 import java.util.ArrayList;
import java.util.List; import static org.junit.Assert.*; public class CommandTest {
@Test
public void main() throws Exception {
Command command = new Command();
String[] args1 = {"-m", "3", "800", "-n", "7"};//正确的参数类型(默认模式)
String[] args2 = {"-m", "50", "400", "-n", "100000"};//参数范围不合法
String[] args3 = {"-m", "3", "800", "-n", "7", "-o", "3", "-b", "-c"};//正确的参数范围(不默认)
String[] args4 = {"-m", "3", "800", "-n", "7", "-o", "你", "-b", "-c"};//参数类型错误
String[] args5 = {"-m", "L", "800", "-n", "7"};//参数类型错误
String[] args6 = {"-m", "3", "800", "-n", "、"};//参数类型错误
String[] args7 = {"-m", "3", "800", "-n", "7", "M"};//输入参数不合法
String[] args8 = {"-m", "3", "800"};//缺少参数 List<String[]> list = new ArrayList();
list.add(args1);
list.add(args2);
list.add(args3);
list.add(args4);
list.add(args5);
list.add(args6);
list.add(args7);
list.add(args8); for (int i = list.size() - 1; i >= 0; i--)
Command.main(list.get(i));
} }

  代码覆盖率如下:

接口类测试覆盖率:

结对作业(web)-LMLPHP

  Command类的测试覆盖率:

结对作业(web)-LMLPHP

  在单元测试中,每个类对应一个测试类,测试类中每个测试方法对应一个方法。构造测试数据时,根据方法中每个分支对应的情况,设置相应的参数,确保测试会进入到每一个分支,达到测试的目的。

 6.计算模块部分异常处理说明

  在计算模块中,用户如果传入不合法参数,程序会捕获异常,显示异常类型并提示错误参数。由于我们的项目是用web实现的,对于不合法的参数(如汉字,符号)以及参数为空这些问题都会在前端进行判断,并提醒用户,所以在异常处理的得上设计中,只做了参数范围不合法一种异常类型,由于题目会有上下界的要求,但当上下界范围较小时,无法产生题目,因此我们设定当上下界只差小于30时,抛出异常,提示用户扩大范围。

当符号数量不在合理范围内时:

 @Test
public void createCharacter() throws Exception { System.out.println(createArithmetic.CreateCharacter(56,true)); }

结对作业(web)-LMLPHP

  当上下界不在合理范围时:

 @Test
public void createNumber() throws Exception {
System.out.println(createArithmetic.CreateNumber(4,-9,800));
}

结对作业(web)-LMLPHP

  当上下界范围太小时:

 @Test
public void createNumber() throws Exception {
System.out.println(createArithmetic.CreateNumber(4,50,60));
}

结对作业(web)-LMLPHP

  当题目数量不在合理范围时:

  @Test
public void createFile() throws Exception {
System.out.println(createArithmetic.createFile(-9,true,true,10,1000,4)); }

结对作业(web)-LMLPHP

7. 界面模块的详细设计过程

  界面模块我们采用jsp结合js完成前端页面的设计,通过servlet完成前后端的交互。

  根据程序所要实现的功能,我们将设计四个页面用来展示并实现这些功能:

  1)home.jsp:主页。有生成题目和上传题目两个按钮,点击不同的按钮进入不同页面,进行相应操作

  2)create_arithmetic.jsp:生成题目页面。页面通过form表单,获取用户输入的参数,生成相应题目,并可供用户下载生成的题目。页面显示每个参数的输入框,提示参数范围,并对必填输入框进行判空;有生成题目和返回(返回主页)两个按钮。

  3)upload _arithmetic.jsp:上传文件页面。用户选择文件上传,上传成功之后点击答题,进入答题页面开始答题。页面显示输入框,用户可选择文件,实现输入框的判空以及文件格式的判断;有上传和返回(返回主页)两个按钮。

  4)do _arithmetic.jsp:答题页面。用户在这个页面可以进行答题。页面会显示题目总数和当前题目序号;显示题目,用户做答;页面有下一题,结束,返回(返回主页)三个按钮,用户可以选择继续答题或结束答题;当做到最后一题时,隐藏下一题的按钮。结束答题之后,页面会显示用户答题数目,答对的题目数量以及花费时间。

  答题页面代码的展示:

 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: 芋头
Date: 2018/4/2
Time: 20:49
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>上传题目</title>
</head>
<body style="margin-left:30px;margin-top:120px;background:url(../../img/bg.jpg)no-repeat ;background-position-x:55%;background-position-y:-10%;padding-top: 20px;font-size: 20px;">
<form action="${website}/arithmetic?state=upload" onsubmit="return checkform()" method="post" enctype="multipart/form-data">
<table style="padding-top: 160px" align="center">
<tr>
<td colspan="2" align="center">
<font style="color:#1e90ff" size="3">${msg}</font>
<a href="${website}/arithmetic?state=toDoArithmetic" style="text-decoration: none "><font style="color:dodgerblue">${msg1}</font></a>
</td>
</tr>
<tr style="height: 15px"></tr>
<tr>
<td><font color="#1e90ff" face="STHupo" size="4">选择一个文件:</font></td>
<td><font color="#1e90ff" face="STHupo" size="4">
<input type="file" name="uploadFile" id="nu"/>
</font>
</td>
</tr>
<tr style="height: 25px">
<td></td>
<td></td>
</tr>
<tr>
<td>
<input type="submit" value="上传" style="width: 80px;height: 40px;border: none;background-color: skyblue;box-shadow: 2px 2px 2px #FFD700;border-radius: 5px;color: white;font-weight: 600;" />
</td>
<td align="right">
<a href="${website}/arithmetic?state=toHome" style="text-decoration: none ">
<input type="button" value="返回" style="width: 80px;height: 40px;border: none;background-color: skyblue;box-shadow: 2px 2px 2px #FFD700;border-radius: 5px;color: white;font-weight: 600;">
</a>
</td>
</tr>
</table>
</form> <script language="javascript" type="text/javascript">
function checkform(){
if(document.getElementById('nu').value.length==0){
alert('您还没有选择文件!');
document.getElementById('nu').focus();
return false;
}
}
</script>
</body>
</html>

8. 界面模块与计算模块的对接

  项目中前后端交互采用servlet实现。当用户发送一个请求,会进入到相应的servlet方法中,在servlet方法中获取对应的参数,调用接口中的方法,并对客户端做出响应。为了提高代码的安全性,jsp页面放在了web-INF目录下面,因此只有通过servlet才能访问到页面。servlet中包含了上传文件,下载文件,读取文件,生成题目,答题以及各个页面之间跳转的方法。其中,在生成题目的方法中会调用CreateArithmetic的接口,在答题的方法中会调用Calculation的接口。

  这里展示部分代码:

 /**
*读取文件内容
* @param request
* @param response
* @throws ServletException
*/
public void read(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{ RequestDispatcher rd = null;
response.setContentType("text/html");
response.setCharacterEncoding("GBK");
PrintWriter out=response.getWriter();
String realPath= request.getParameter("path");
List<String> list = new ArrayList<>();
File file=new File(realPath);
if(file.exists()){
FileReader reader=new FileReader(file);
BufferedReader bufferedReader=new BufferedReader(reader);
String line =null;
while((line=bufferedReader.readLine())!=null)
{
list.add(line);
}
reader.close();
bufferedReader.close();
}else{
out.print("file is not exist!");
out.close();
}
request.getSession().setAttribute("list",list);
System.out.println();
request.setAttribute("msg1","题目上传成功,点击这里开始答题!");
rd = request.getRequestDispatcher(WebContents.UPLOAD);
rd.forward(request,response);
}

  实现的功能:

结对作业(web)-LMLPHP  结对作业(web)-LMLPHP

结对作业(web)-LMLPHP  结对作业(web)-LMLPHP

9.描述结对的过程

  本次作业,我们两个人在工作室完成结对编程的。本次编程过程中,我们两个人都有明确的分工,一人负责一个模块,过程虽然有点困难,但是我们也充分的感受到了合作的重要性。尤其是在编程过程中,明白了自己设计的东西要简单易懂,让人能一眼看懂。

讨论照片展示:

结对作业(web)-LMLPHP   结对作业(web)-LMLPHP

10.结对编程的优缺点

  结对编程优点:

  1.结对编程就是两个程序员互相审查的过程,在编程过程中能够尽早发现问题并解决问题,提高了编程效率。

  2.编程过程中遇到瓶颈两个人相互鼓励,极大的提高了编程的积极性。

  3.两个人在编程过程中不断磨合,相互学习,使双方的代码能力得到了一定程度上的增强,同时也有了合作意识。

  结对编程缺点:

  1.一个人独立钻研的时候,两个人思路会不同,编程方法也不同,需要时间来抉择用哪一个方法,需要磨合时间

  马玲优点:

  1.编程能力强,认真

  2.对于模块独立化有独特的见解

  3.逻辑思维能力强,编程严谨

  马玲缺点:

  1.不够细心,经常会忽略一些细节,考虑不够全面

  王雪优点:

  1.遇到bug有耐心解决

  2.注重细节,努力

  3.态度积极,乐于学习

  王雪缺点:

  1.编程经验不足,对程序把握不够

11.实际花费的时间PSP表格

PSP

任务内容

实际时间(min)

Planning

计划

50

Estimate

估计这个任务需要多少时间,并规划大致工作步骤

30

Development

开发

1560

Test

测试

110

Algorithm Optimization

算法优化

200

Interface Design

接口设计

160

Coding Standard

代码规范

60

Design

具体设计

160

Coding

具体编码

600

Code Review

代码复审

60

Test

测试

150

Reporting

报告

120

Test Report

测试报告

100

Size Measurement

计算工作量

30

Postmortem & Process Improvement Plan

事后总结, 并提出过程改进计划

150

12.总结与修改

    在后面老师给的时间段里,我们两个人在之前的代码基础上修改了一些功能。在效能分析这一模块中,我们做了更近一步的完善,在博客中做了相应的补充。在项目功能这一模块,我们加入了用户登录和注册,实现了用户可以查看自己答题记录的功能。但我们的项目中也存在很多不足,对于前端展示页面,由于我们这方面知识的欠缺,所以完成的并不是很好,以后的作业中我们会不断完善,改进自己的不足。

增加的功能展示:

结对作业(web)-LMLPHP  结对作业(web)-LMLPHP

结对作业(web)-LMLPHP

结对作业(web)-LMLPHP

结对作业(web)-LMLPHP

结对作业(web)-LMLPHP


05-11 20:19