结对项目作业

1. Coding.net地址

https://git.coding.net/Agustin_Leonard_DPS/TEAM_TWO.git
 
此Coding.net 为我与方柱权两人的共同项目
许征航 2016012096   方柱权2016042033

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:信息隐藏。

        信息隐藏是程序设计过程中的一种隔离原则,可以防止用户接触到一个类的某些部分。用户并不关心你的代码实现方式,甚至于程序设计者还要避免用户接触到你的代码的内容,引起不必要的代码崩溃。所以程序设计者可以使用信息隐藏的方式,避免用户对代码内容产生影响。并且可以实现功能的模块化,来进行构架。

    Interface Design:接口设计。

         1.一个接口只服务于一个子模块或业务逻辑。
   2.通过业务逻辑压缩接口中的public方法,接口时常去回顾,尽量让接口达到“满身筋骨肉”,而不是“肥嘟嘟”的一大堆方法。
   3.已经被污染了的接口,尽量去修改,若变更的风险较大,则采用适配器模式进行转化处理。
   4.了解环境,拒绝盲从。每个项目或产品都有特定的环境因素,不要盲从大师的设计,要根据业务逻辑进行最好的接口设计。

    Interface Design:松耦合。

        低耦合要求:
  1.只和朋友交流
    朋友类:出现在成员变量、方法的输入输出参数中的类。方法体内部的类不属于朋友类。
  2.朋友间也是有距离的
    迪米特法则要求类“羞涩”一点,尽量不要对外公布太多的public方法和非静态的public变量,尽量内敛,多使用private、package-private、protected等访问权限。
  3.是自己的就是自己的
    如果一个方法放在本类中,既不增加类间关系,也对本类不产生负面影响,就放置在本类中。
  4.谨慎使用Serializable

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");
    }
}
View Code

  单元测试代码覆盖率如下:

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的方式,提供给用户信息上传的功能,之后调用计算模块进行生成。

  

  两个不会美工的人做的比较丑,还请见谅。

  之后是完善后的做题页面。

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

  我们主要使用文本框读入相关信息,监听器监听监听JButton事件,读取文本框内容。将参数传入makeQuestions方法进行生成。

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);

        }
}

10. 以下为结对过程中两人的想法交流, 算法和GUI模块相连时的讨论

11.结队感想

  优点:

    1. 两个人结对有着很好的互补作用,你不必完成所有的工作,分工合理两个人都会比较轻松。

     在此次的结对中,我主要负责算法模块的实现,并编写方法供用户界面调用,而我的partner方柱权主要负责图形用户界面,以及界面之间的跳转,以及函数调用及实现。在此次结对中,良好的分工造就了良好的效率以及很好的工作体验。

    2. 你的不足会有别人指出,你的想法会有队友完善。

     在此次结对中,算法模块是我比较熟练也是压力较小的工作,而单元测试和代码覆盖率以及命令行调试和异常处理部分,是我负责却又较为薄弱的部分,在项目的完成中学习了很多新的内容,期间权权也给了我很多的建议和鼓励,例如在设置上下界时还应该判断上界是否会小于下界这样的小问题。

    3. 优秀的队友是成功的一半。

     在此次结对中,我很庆幸我是和权权一组的,因为在整个结对过程中个,权权都在很认真努力的完成自己负责的部分。当然会有卡壳的地方,但他总是会和我积极讨论,我的问题我改,他的错误他纠正。这种沟通交流促进我们双方的进步,也使得这次项目完成顺利。

  缺点:

    1. 两人时间上的冲突

      我因为蓝桥杯,校赛的比赛。还要争夺东北赛,西安邀请赛,徐州邀请赛校内名额,还有本周末的创新创业大赛,白天的时间都泡在实验室中进行训练。只有晚上才可以整理这次的项目内容,并和队友交流。期间我们有很多问题我都无法及时回复,造成了项目进度进展缓慢的结果。这点也是我对队友感到十分抱歉的一点。

      我们是学生,我们作为学生这个角色的任务不止这门课一个,而这门课所花费的时间是其他很多任务的时间之和。我很感激我能在这门课中学到很多,但是同时,每个学生的实际情况也是不同的,我们所处的环境也是不同的。时间是一个不会因为你去祈祷而会慢慢走的东西,我们的压力不止来源于这一门课,于我本人而言算法和竞赛是我现在的主攻方向,也确实分去了我相当多的时间和精力。如果说“人只要努力,时间只要挤,信念只要足够坚定,你的压力都是你的动力”,那么我想说,当10公斤的铁块压在蚂蚁的身上,只有两种结果,蚂蚁被压死,或者蚂蚁在地缝中逃走。甚至不用10公斤,1公斤对于蚂蚁而言就已经是很难承受的了。或者说,我菜我懒我没用,但我想说,我真的很累。

      人异者,时同境非,因材施教,同规异果。

End

原文地址:https://www.cnblogs.com/ShadowGhostH/p/8763039.html