四则运算结对项目
Posted max793
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了四则运算结对项目相关的知识,希望对你有一定的参考价值。
最初项目为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="width: 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="width: 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以上是关于四则运算结对项目的主要内容,如果未能解决你的问题,请参考以下文章