四则运算结对项目

最初项目为GUI形式,两人合作完成;延期改进过程结对队员休学,因此由个人改为网页版形式并实现后续功能添加,但部分功能未完善

1.代码地址https://git.coding.net/mx123422/WebCalculate-master.git

   URL地址:http://39.105.6.214/WangYeBan_war/

2.PSP计划

PSP2.1

任务内容

计划共完成需要的时间(h)

Planning

计划

2

·        Estimate

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

2

Development

开发

65

·        Analysis

·         需求分析 (包括学习新技术)

5

·        Design Spec

·         生成设计文档

2

·        Design Review

·         设计复审 (和同事审核设计文档)

1

·        Coding Standard

·         代码规范 (为目前的开发制定合适的规范)

10

·        Design

·         具体设计

5

·        Coding

·         具体编码

30

·        Code Review

·         代码复审

6

·        Test

·         测试(自我测试,修改代码,提交修改)

6

Reporting

报告

3

·         Test Report

·         测试报告

1

·         Size Measurement

·         计算工作量

1

·         Postmortem & Process Improvement Plan

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

1

3.接口

(1)Information Hiding信息隐藏

信息隐藏指在设计和确定模块时,使得一个模块内包含的信息(过程或数据),对于不需要这些信息的其他模块来说,是不能访问的。通过信息隐藏,可以定义和实施对模块的过程细节和局部数据结构的存取限制。

信息隐藏有着独特的启发力,它能够激发出有效的设计方案。信息隐藏同样有助于设计类的公开接口。在设计的所有层面上,都可以通过询问该隐藏些什么来促成好的设计决策。

(2)Interface Design接口设计

模块间的接口分类:参数传递,全局变量,文件

设计原则:

低耦合,高内聚;两个耦合的模块间以数据耦合为最佳,即除了调用时传参数以外不存在其他关系。

设计要点:

模块功能力求单一,即一个模块只做一件事;模块的输入输出数据全部组织成为调用参数且当被调用时实参和形参要保持一致

本次项目在生成运算式与计算数值中使用到了接口。

(3)Loose Coupling松耦合

模块与模块之间总会存在一些“联系”,这就会提升我们维护过程中的复杂度和任务量。松耦合通过接口的方式实现各个模块之间的调用,可以使模块在发生改变时,其他的部分可以保持不变,减少模块间的相互“联系”,降低耦合。

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

(1)SuanShi.java

此接口对于题目中仅加减、是否含乘除法、是否含括号含三个方法,接受来自Choose.jsp界面输入的题目数、绝对值上下限及运算符个数,从而完成Main.java中对于生成计算式的实现;同理也可从命令行接受来自Command.java中的参数进行运算式生成。

(2)Calculate

此接口中的方法对来自SuanShi.Java中生成字符串型运算式的求值。

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

项目总体分析图,从内存,多线程,CPU等方面分析了计算模块的性能,截图如下:

 

代码覆盖率:

 

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

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

 输入参数不合法:

 1 import java.io.PrintStream;
 2 import java.util.Scanner;
 3 
 4 public class Command {
 5     static YunSuanShiShengCheng expression=new YunSuanShiShengCheng();
 6     public static int n;//题目数
 7     public static int m1;//范围下限
 8     public static int m2;//范围上限
 9     public static int b = 0;//题目中是否有括号,默认没有
10     public static int c = 0;//题目中是否有乘除法,默认没有
11     public static int o = 1;//运算符个数,默认为1
12 
13     
14 
15     public static void main(String[] args) {
16         // TODO Auto-generated method stub
17         int isN = 0;
18         int isM = 0;
19         /*n = 10;
20         m1 = 1;
21         m2 = 50;
22         c=0;
23         o=4;
24         b=1;*/
25         for (int i = 0; i < args.length; i++) {
26             if (args[i].equals("-n")) {
27                 isN = 1;
28                 try {
29                     n = Integer.parseInt(args[i + 1]);
30                     if (n <= 0 || n > 10000) {
31                         System.out.println("n的范围不在[1,10000]内,请重新输入");
32                         return;
33                     }
34                 } catch (Exception e) {
35                     System.out.println("n的格式不合法,请重新输入!");
36                 }
37             }
38             if (args[i].equals("-m")) {
39                 isM = 1;
40                 try {
41                     m1 = Integer.parseInt(args[i + 1]);
42                     m2 = Integer.parseInt(args[i + 2]);
43                     if (m1 <= 0 || m1 > 100) {
44                         System.out.println("m1的范围不在[1,100]内,请重新输入");
45                         return;
46                     }
47                     if (m2 < 50 || m2 > 1000) {
48                         System.out.println("m1的范围不在[50,1000]内,请重新输入");
49                         return;
50                     }
51                 } catch (Exception e) {
52                     System.out.println("m的格式不合法,请重新输入!");
53                 }
54             }
55             
56             if (args[i].equals("-o")) {
57                 try {
58                     o = Integer.parseInt(args[i + 1]);
59                     if (o <= 0 || o > 10) {
60                         System.out.println("o的范围不在[1,10]内,请重新输入");
61                         return;
62                     }
63                 } catch (Exception e) {
64                     System.out.println("o的格式不合法,请重新输入!");
65                 }
66             }
67             if (args[i].equals("-b")) {
68                 b = 1;// 括号
69             }
70             if (args[i].equals("-c")) {
71                 c = 1;// 乘除
72             }
73         }
74         if (isN == 0) {
75             System.out.println("无参数n,请重新输入!");
76             return;
77         }
78         if (isM == 0) {
79             System.out.println("无参数m,请重新输入!");
80             return;
81         }
82         
83         System.out.println("生成"+n+"道算术题,每道题目与中间结果的绝对值应该在"+m1+"到"+m2+"之间,算术题中的符号有"+o+"个。");
84         
85         if (b == 0&&c==0) {            
86             expression.generateExpressionA(o,m1,m2,n);
87         } 
88         else if(b == 0&&c==1){
89             expression.generateExpressionD(o,m1,m2,n);
90         } 
91         else if((c == 0)&&b==1){
92             expression.generateExpressionB(o,m1,m2,n);
93         }
94         else
95             System.out.println("请重新输入!");
96         //System.out.println("成功");
97     }
98 
99 }

 

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

 

该页面为Choose.jsp文件,提交输入参数至Choose_chuli.jsp,判断参数输入是否合法 

 1 <div class="main">
 2           
 3             <h1>选择类型</h1>
 4             <div class="inset">
 5 
 6                 <form action="Choose_chuli.jsp" method="post">
 7                     <div>
 8                         <span> <label>运算类型</label>
 9                         </span> <span> <select name="leixing" style=" 100%">
10                                 <option value="1" selected="selected">加减法</option>
11                                 <option value="2">乘除法</option>
12                                 <option value="3">含括号</option>
13                         </select>
14                         </span>
15                     </div>
16                     <div>
17                         <span> <label>运算符个数</label>
18                         </span> <span> <select name="yunsuanfu" style=" 100%">
19                                 <option value="1" selected="selected">1</option>
20                                 <option value="2">2</option>
21                                 <option value="3">3</option>
22                                 <option value="4">4</option>
23                                 <option value="5">5</option>
24                                 <option value="6">6</option>
25                                 <option value="7">7</option>
26                                 <option value="8">8</option>
27                                 <option value="9">9</option>
28                                 <option value="10">10</option>
29                         </select>
30                         </span>
31                     </div>
32 
33 
34                     <div>
35                         <span><input type="text" name="fanweix" placeholder="范围下限" class="textbox"></span>
36                     </div>
37                     <div>
38                         <span><input type="text" name="fanweis" placeholder="范围上限" class="textbox"></span>
39                     </div>
40                     <div>
41                         <span><input type="text" name="num" placeholder="题目个数" class="textbox"></span>
42                     </div>
43                     <div class="sign">
44                         <input type="submit" value="确定" class="submit"  />
45 
46                     </div>
47                 </form>
48             </div>
49         </div>

 

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

(1)根据Choose_chuli.jsp判断参数合法,若合法则传参至SuanShi.java生成符合要求的算式,然后通过DoFile.java写入文件

 1 <%
 2                 request.setCharacterEncoding("utf-8");
 3                 String leixing = request.getParameter("leixing");//三种类型
 4                 String yunsuanfu = request.getParameter("yunsuanfu");//运算符个数
 5                 String fanweix = request.getParameter("fanweix");//范围下限
 6                 String fanweis = request.getParameter("fanweis");//范围上限
 7                 String num = request.getParameter("num");//题目数量
 8 
 9                 
10                 int a, b, c, d, e;
11                 a = Integer.valueOf(request.getParameter("leixing"));
12                 b = Integer.valueOf(request.getParameter("yunsuanfu"));
13                 c = Integer.parseInt(fanweix);
14                 d = Integer.parseInt(fanweis);
15                 e = Integer.parseInt(num);
16 
17                 if (a == 3 && b == 1) {
18                     out.print("无法生成此类型算式!!");
19                     out.print("<a href='Choose.jsp'>重新选择</a>");
20                 } else {
21                     if (c >= d) {
22                         out.print("运算结果受限!");
23                         out.print("<a href='Choose.jsp'>重新选择</a>");
24                     } else {
25                         if (e < 0) {
26                             out.print("输入题目数量错误!");
27                             out.print("<a href='Choose.jsp'>重新选择</a>");
28                         } else if (e > 10000) {
29                             out.print("超出题目数量!");
30                             out.print("<a href='Choose.jsp'>重新选择</a>");
31                         } else {
32 
33                             SuanShi expression = new SuanShi();
34                             switch (a) {
35                             case 1:
36                                 expression.generateExpression1(b, c, d, e);
37                                 break;
38                             case 2:
39                                 expression.generateExpression2(b, c, d, e);
40                                 break;
41                             case 3:
42                                 expression.generateExpression3(b, c, d, e);
43                                 break;
44                             }
45 
46                             response.sendRedirect("Answer.jsp");
47                         }
48                     }
49                 }
50             %>

(2)Answer.jsp从生成的文件中读取算式,用户输入结果,将结果提交至Chengji_choose.jsp,该文件使用<%@  page import="com.Calculate"%>来计算生成文件内每个算式结果,并与用户提交结果对比。最后显示总成绩。

Calculate.java
package com;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;

import java.util.Stack;

public class Calculate {



    private Stack<BigDecimal> numbers = new Stack<BigDecimal>();
    
    private Stack<Character> chs = new Stack<Character>();

    @SuppressWarnings("unused")
    private Object org;
  
    /**
     * 比较当前操作符与栈顶元素操作符优先级,如果比栈顶元素优先级高,则返回true,否则返回false
     *
     * @param str
     *            需要进行比较的字符
     * @return 比较结果 true代表比栈顶元素优先级高,false代表比栈顶元素优先级低
     */
    private boolean compare(char str) {
        if (chs.empty()) {
            // 当为空时,显然 当前优先级最低,返回高
            return true;
        }
        char last = (char) chs.lastElement();
        switch (str) {
        case '*': {
            // '*/'优先级只比'+-'高
            if (last == '+' || last == '-')
                return true;
            else
                return false;
        }
        case '/': {
            if (last == '+' || last == '-')
                return true;
            else
                return false;
        }
            // '+-'为最低,一直返回false
        case '+':
            return false;
        case '-':
            return false;
        }
        return true;
    }
  
    public BigDecimal caculate(String st) {
        StringBuffer sb = new StringBuffer(st);
        StringBuffer num = new StringBuffer();
        String tem = null;
        char next;
        while (sb.length() > 0) {
            tem = sb.substring(0, 1);// 获取字符串的第一个字符
            sb.delete(0, 1);
            if (isNum(tem.trim())) {
                num.append(tem);// 如果是数字,将其放入num当中
            } else {
  
                if (num.length() > 0 && !"".equals(num.toString().trim())) {// 当截取的字符不是数字时,则认为num中放置的时一个完整的数字,
                    // 如123+1,当获取到+时,前面的123可以认为是一个完整的数
                    BigDecimal bd = new BigDecimal(num.toString().trim());
                    numbers.push(bd);
                    num.delete(0, num.length());
                }
                // 如果chs为空,这认为这时第一个字符直接放入
                if (!chs.isEmpty()) {
                    // 当当前的运算符优先级等于或者小于栈顶得预算符时,做运算.
                    // 例如,1+2+3,当截取到2,3之间的“+”与1,2之间的"+"优先级相等时,可以先计算1+2,使其变成3+3
                    // 同样,1*2+3,当截取到2,3之间的“+”与1,2之间的"*"优先级小,可以先计算1*2,使其变成2+3
  
                    while (!compare(tem.charAt(0))) {
                        caculate();
                    }
                }
                // 当数字栈也为空时,既运算式的第一个数字为负数时
                if (numbers.isEmpty()) {
                    num.append(tem);
                } else {
                    chs.push(new Character(tem.charAt(0)));
                }
                // 判断后一个字符是否为“-”号,为"-"号时,认为数字为负数
                // 例如 1*2*(-5),因为此运算不计算(),因此将被改写为1*2*-5,如此情况,须将"-"认为是负数表达式而非减号
                next = sb.charAt(0);
                if (next == '-') {
                    num.append(next);
                    sb.delete(0, 1);
                }
  
            }
        }
        // 由于前面将数字放入栈时,是通过获取符号为时处理,导致最后一个数字没有放入栈中,因此将最后的数字放入栈中
        BigDecimal bd = new BigDecimal(num.toString().trim());
        numbers.push(bd);
        // 此时符号栈上最多只有2个符号,并且栈顶得符号优先级高,做运算
        while (!chs.isEmpty()) {
            caculate();
        }
        return numbers.pop();
    }
  
    private void caculate() {
        BigDecimal b = numbers.pop();// 第二个运算数
        BigDecimal a = null;// 第一个运算数
        a = numbers.pop();
        char ope = chs.pop();
        BigDecimal result = null;// 运算结果
        switch (ope) {
        // 如果是加号或者减号,则
        case '+':
            result = a.add(b);
            // 将操作结果放入操作数栈
            numbers.push(result);
            break;
        case '-':
            // 将操作结果放入操作数栈
            result = a.subtract(b);
            numbers.push(result);
            break;
        case '*':
            result = a.multiply(b);
            // 将操作结果放入操作数栈
            numbers.push(result);
            break;

        case '÷':
            result = a.divide(b);// 将操作结果放入操作数栈
            numbers.push(result);
            break;
        }
        
    }
  
    private boolean isNum(String num) {
        return num.matches("[0-9]");
    }
      
    /**未实现
     *
     * 功能描述。
     * 解析,将带有括号的运算符变成没有带括号的字运算
     */
        public BigDecimal parse(String st) {
            int start = 0;
            StringBuffer    sts = new StringBuffer(st);
            int end = -1;
            while ((end = sts.indexOf(")")) > 0) {
                String s = sts.substring(start, end + 1);
                int first = s.lastIndexOf("(");
                BigDecimal value = caculate(sts.substring(first + 1, end));
                sts.replace(first, end + 1, value.toString());
            }
            return caculate(sts.toString());
        }
        
        
        
        
}

10.描述结对的过程

此次项目的后续改进中无结对过程,原因在于项目改进时结对队员休学,原版项目为客户端GUI页面,此次项目的网页版由个人单独完成。

成员:

马雪        2016012093 

王亚楠    

(1)结对优点

程序员互相帮助,互相教对方,可以得到能力上的互补。

可以让编程环境有效地贯彻Design。

增强代码和产品质量,并有效的减少BUG。

降低学习成本。一边编程,一边共享知识和经验,有效地在实践中进行学习。

在编程中,相互讨论,可能更快更有效地解决问题。

(2)结对缺点

于有不同习惯的编程人员,可以在起工作会产生麻烦,甚至矛盾。

有时候,程序员们会对一个问题各执己见(代码风格可能会是引发技术人员口水战的地方),争吵不休,反而产生重大内耗。

两个人在一起工作可能会出现工作精力不能集中的情况。程序员可能会交谈一些与工作无关的事情,反而分散注意力,导致效率比单人更为低下。

个人优点:不松懈、努力、不懂就问

个人缺点:缺少耐心

队员优点:冷静、积极、技术性指导

队友缺点:办事心切,处事不够干练

12.PSP实际

PSP2.1

任务内容

实际完成需要的时间(h)

Planning

计划

3

·        Estimate

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

3

Development

开发

100

·        Analysis

·         需求分析 (包括学习新技术)

5

·        Design Spec

·         生成设计文档

5

·        Design Review

·         设计复审 (和同事审核设计文档)

0

·        Coding Standard

·         代码规范 (为目前的开发制定合适的规范)

20

·        Design

·         具体设计

10

·        Coding

·         具体编码

40

·        Code Review

·         代码复审

10

·        Test

·         测试(自我测试,修改代码,提交修改)

10

Reporting

报告

6

·         Test Report

·         测试报告

2

·         Size Measurement

·         计算工作量

2

·         Postmortem & Process Improvement Plan

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

2

原文地址:https://www.cnblogs.com/mx123422/p/8764316.html