1. Coding.net地址
2. PSP分享
PSP2.1 |
任务内容 |
计划共完成需要的时间(min) |
实际完成需要的时间(min) |
Planning |
计划 |
20 |
30 |
· Estimate |
· 估计这个任务需要多少时间,并规划大致工作步骤 |
20 |
30 |
Development |
开发 |
280 |
277 |
· Analysis |
· 需求分析 (包括学习新技术) |
60 |
125 |
· Design |
· 具体设计 |
30 |
50 |
· Coding |
· 具体编码 |
120 |
153 |
· Code Review |
· 代码复审 |
20 |
17 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
50 |
32 |
Reporting |
报告 |
75 |
182 |
· Test Report |
· 测试报告 |
15 |
20 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
60 |
162 |
3. 相关概念
Information Hiding:信息隐藏。
信息隐藏是程序设计过程中的一种隔离原则,可以防止用户接触到一个类的某些部分。用户并不关心你的代码实现方式,甚至于程序设计者还要避免用户接触到你的代码的内容,引起不必要的代码崩溃。所以程序设计者可以使用信息隐藏的方式,避免用户对代码内容产生影响。并且可以实现功能的模块化,来进行构架。
4.计算模块设计
计算模块我们小组使用了之前我在个人项目中的计算模块,依旧是将计算用代码封装在Lib.java中,然后在Command.java中调用Lib中的方法进行计算。
实现逻辑上依旧是:出题(makeQuestions) 做题(calQuestion)印题(filePrint)三个方法。
而因为在第一次的个人项目中,就已经在makeQuestion方法中设置了参数,并且将随机数产生器单独列为一个方法(makeRandom),所以在这次的作业中可以很好的控制题目个数、数据范围、操作符个数。
因为这次作业是在个人项目算法上进行的,几乎没有变动(很感激上一次的完善),所以这次也就不再赘述了。
5.计算模块性能改进
顺序生成,特判处理,没有数据结构和贪心的优化,对于n个m操作符的算式,时间复杂度为O(n*m),属于较优算法,无需改进。
6.单元测试展示
单元测试是这次新学到的东西,期间查阅了很多资料也很感谢邹欣老师所给出的博客指导,单元测试部分针对Lib.class进行,使用JUnit 4。单元测试代码如下:

import static org.junit.Assert.*; import java.io.IOException; import org.junit.Test; public class LibTest { public static Lib test = new Lib(); public static int ans; public String[] questionList = new String[100]; @Test public void testMakeQuestions() { Lib.makeQuestions(questionList, 5, 5, 1, 100, true, true); Lib.makeQuestions(questionList, 5, 5, 1, 100, true, false); Lib.makeQuestions(questionList, 5, 5, 1, 100, false, true); Lib.makeQuestions(questionList, 5, 5, 1, 100, false, false); //assertEquals(2, test.getresult()); } @Test public void testCalQuestion() { assertEquals(77, Lib.calQuestion("(34-29)+52*1+10*2")); assertEquals(47, Lib.calQuestion("3+5*(2+4*2)-6")); assertEquals(6, Lib.calQuestion("1+2*3-4+9÷3")); assertEquals(4, Lib.calQuestion("(2+4-3)÷3+5-2")); //assertEquals(77, Lib.calQuestion("(34-29)+52*1+10*2")); } // @Test // public void testGetw() { // assertEquals(1, Lib.getw('+')); // assertEquals(1, Lib.getw('-')); // assertEquals(2, Lib.getw('*')); // assertEquals(2, Lib.getw('÷')); // assertEquals(3, Lib.getw('(')); // assertEquals(-1, Lib.getw(')')); // assertEquals(-1, Lib.getw('#')); // } @Test public void testFilePrint() throws IOException { Lib.filePrint(questionList, 5, "test.txt"); } @Test public void testFileScanf() throws IOException{ Lib.filePrint(questionList, 5, "test.txt"); Lib.fileScanf(questionList, "test.txt"); } }
单元测试代码覆盖率如下:
7.计算模块部分异常处理说明
因为Command.java部分是这次新写的,所以贴出代码并进行分析。
import java.io.IOException; public class Command { public static void main(String args[]) { String[] questionList = new String[105]; String path = "result.txt"; int sum = 0, ops = 1, minn = 1, maxx = 100; boolean have_lv2_ops = false, have_bracket = false; try { for(int i=0; i<args.length; i++) { if(args[i].equals("-n") ) { sum = Integer.parseInt(args[++i]); if(sum<0) { System.out.println("错误:设置的题目个数应为正整数"); return; } } else if(args[i].equals("-m")) { minn = Integer.parseInt(args[++i]); maxx = Integer.parseInt(args[++i]); if(minn>maxx) { System.out.println("错误:设置的最小值 :" + minn + "大于设置的最大值" + maxx); return; } else if(maxx>1000 || minn<1) { System.out.println("错误:设置的取值范围应在[1, 1000]之间"); return; } } else if(args[i].equals("-o")) { ops = Integer.parseInt(args[++i]); if(ops<0) { System.out.println("错误:设置的操作符个数应为正整数"); return; } } else if(args[i].equals("-c")) { have_lv2_ops = true; } else if(args[i].equals("-b")) { have_bracket = true; } else { System.out.println("错误: " + args[i] + "不是一个有效的命令,请输入有效的命令(-n, -m, -o, -c, -b)"); return; } } } catch (Exception e) { System.out.println("请输入有效的命令及其对应的参数"); System.out.println("设置题目个数为sum: -n sum sum为正整数"); System.out.println("设置题目上下界为[min, max]: -m min max min maxx应在[1, 1000]之间 "); System.out.println("设置题目操作符个数为ops: -n ops"); System.out.println("设置题目中含有乘除法: -c"); System.out.println("设置题目中含有括号: -b"); } Lib.makeQuestions(questionList, sum, ops, minn, maxx, have_lv2_ops, have_bracket); try { Lib.filePrint(questionList, sum, path); } catch(IOException ioe) { ioe.printStackTrace(); } } }
在命令行测试中,对用户输入的命令即其参数进行判断:
1. 当输入的不是应有命令时,对用户做出提醒,输入正确的命令,列出合法命令
2.当用户输入的参数错误时,对用户做出提醒,并解释各个参数的写法及各个命令的含义
3.对于合法的命令和参数,对参数进行检查,看是否符合要求:不能出现负数题数,负数符号数,下界不能大于上界等。
4.以下是命令行调试及异常处理及给用户的相关提示。
8. 界面模块设计
在本次的分工中,我主要负责计算模块、单元测试部分,我的队友则负责UI界面设计及功能调用。在我们此次的UI界面设计中,我们使用java GUI的方式,提供给用户信息上传的功能,之后调用计算模块进行生成。
两个不会美工的人做的比较丑,还请见谅。
之后是完善后的做题页面。
import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.IOException; import javax.swing.*; public class GUI extends JFrame{ private JTextField sum = new JTextField(5); private JTextField min = new JTextField(2); private JTextField max = new JTextField(2); private JTextField ops = new JTextField(4); private JRadioButton b2 = new JRadioButton(); private JRadioButton b1 = new JRadioButton(); private JButton Cre = new JButton("开始生成!"); public GUI() { Font font = new Font("SansSerif",Font.BOLD,18);//设定字体 Font font2 = new Font("SansSerif",Font.CENTER_BASELINE,26); Color color = new Color(50,150,50); JPanel p1 = new JPanel(); JLabel title = new JLabel("欢迎使用四则运算题目生成系统!"); title.setFont(font2); p1.add(title,BorderLayout.CENTER); //p1为标题 JPanel p2 = new JPanel(); p2.setLayout(new FlowLayout(FlowLayout.CENTER,10,20)); JLabel NOQ= new JLabel("需要的题目数量(1~10000):"); NOQ.setFont(font); p2.add(NOQ); p2.add(sum);//p2设定为题目数 JPanel p3 = new JPanel(); JLabel RON = new JLabel("题目的数值范围(下界1~100,上界50~1000):"); RON.setFont(font); p3.add(RON); p3.add(min); p3.add(max);//p3设定上下界 //System.out.println(min1); JPanel p4 = new JPanel(); JLabel NOO = new JLabel("题目中最多存在运算符数量:"); NOO.setFont(font); p4.add(NOO); p4.add(ops);//p4设定运算符数量 JPanel p5 = new JPanel(); JLabel isMul = new JLabel("题目中是否有乘除法(默认为无):"); isMul.setFont(font); p5.add(isMul); p5.add(b2);//设定乘除 JPanel p6 =new JPanel(); JLabel isBracket = new JLabel("题目中是否有括号(默认为无):"); isBracket.setFont(font); p6.add(isBracket); p6.add(b1); p6.setFont(font);//设定括号 JPanel p7 =new JPanel(); Cre.setFont(font); Cre.setBackground(color); p7.add(Cre,BorderLayout.WEST); JButton exit = new JButton("退出系统"); exit.setFont(font); exit.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { System.exit(0); } }); exit.setBackground(new Color(200,250,250)); exit.setForeground(new Color(0,0,0)); p7.add(exit,BorderLayout.EAST); setLayout(new GridLayout(7,1,5,2)); add(p1); add(p2); add(p3); add(p4); add(p5); add(p6); add(p7); Cre.addActionListener(new ButtonListener()); } public boolean actionPerformed(ActionEvent e ,JRadioButton b) { if(b.isSelected()) return true; else return false; } private class ButtonListener implements ActionListener{ public void actionPerformed(ActionEvent e) { int sum1 = Integer.parseInt(sum.getText()); int min1 = Integer.parseInt(min.getText()); int max1 = Integer.parseInt(max.getText()); int ops1 = Integer.parseInt(ops.getText()); String path = "result.txt"; boolean have_Mul = GUI.this.actionPerformed(e ,b2); boolean have_Bra = GUI.this.actionPerformed(e ,b1); //System.out.println(sum1+" "+min1+" "+max1+" "+ops1+" "+have_Mul+" "+have_Bra); String[] questionList = new String[sum1+3]; Lib.makeQuestions(questionList, sum1, ops1, min1, max1, have_Mul, have_Bra); try { Lib.filePrint(questionList, sum1, path); } catch(IOException ioe) { ioe.printStackTrace(); } } } public static void main(String[] args) { GUI frame = new GUI(); frame.setTitle("四则运算题目生成系统"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); frame.setSize(1000,800); } }