• 结对作业


    前言:

    四则运算结对项目成果展示,动手实现之前困惑忐忑,开发过程中劳累又收获,项目完成后满足又成长许多。

     

    正文:

    一:项目地址

    Coding.net项目地址:https://git.coding.net/Meloody/jieduizuoye.git

     

    二:预计时间

    PSP表格展示:

     

    任务内容

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

    实际完成需要的时间

    (min)

    Planning

    计划

    30

    *

    · Estimate

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

    10

    *

    Development

    开发

    1250

    *

    ·Analysis

    ·需求分析 (含有学习新技术)

    300

    *

    ·Design Spec

    ·生成设计文档

    20

    *

    ·Design Review

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

    10

    *

    ·Coding Standard

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

    15

    *

    ·Design

    ·具体设计

    30

    *

    ·Coding

    ·具体编码

    600

    *

    ·Code Review

    ·代码复审

    30

    *

    ·Test

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

    200

    *

    Modular

    模块

    600

    *

    ·Computing module 计算模块 400 *
    ·Timing module 计时模块 200 *

    Reporting

    报告

    490

    *

    ·Test Report

    ·测试报告

    420

    *

    ·Size Measurement

    ·计算工作量

    40

    *

    ·Postmortem & Process Improvement Plan

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

    30

    *

    三:接口设计

      结合Information Hiding, Interface Design, Loose Coupling的知识,说明在结对编程中是如何利用这些方法对接口进行设计的。(3')

     

      Information Hiding方法的知识: 它是什么?是信息隐藏,指在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是不可访问的。为什么要隐藏?首先可以隐藏复杂度:这样你就不用再去应付它,除非你要特别关注的时候;其次隐藏变化源:这样当变化发生时,其影响就能被限制在局部范围内。复杂度的根源包括复杂的数据类型、文件结构、布尔判断以及晦涩的算法等等。信息隐藏的价值:信息隐藏有着独特的启发力,它能够激发出有效的设计方案。信息隐藏同样有助于设计类的公开接口。在设计的所有层面上,都可以通过询问隐藏什么的方式达到好的设计决策。 

      

      Information Hiding方法的接口设计把类内数据误认为全局变量:为了避免全局数据可能带来的问题,可能会把类内数据误认为是全局数据并避免使用它,我们把Expression.java的answer变量由最初的全局变量变为类内数据,因为Judge.java里面有一个answer变量,为了避免Judge.java使用Expression.java的answer,我们把Judge.java的answer变量改为了ans变量名。其实只要Expression.java的answer变量的位置处于局部变量的位置就可以避免了。

     

      Interface Design方法的知识: 是什么?是接口设计,接口是一种与类相似的结构,只包含常量和抽象方法。一句简单又非常具有概括性的话:接口可以继承接口,类只能实现接口(参看博客1)。

     

       Interface Design方法的接口设计通过参数传值,类间调用等实现模块的对接(主要是Command类和Expression类)。

     

      Loose Coupling方法的知识:是什么?是松耦合,想让对象与对象间松耦合,通过增加抽象类(Abstract Class)或者接口来做到。松耦合主要用来处理可伸缩性、灵活性和容错这些需求。松耦合的目标是最小化依赖。要实现松耦合,通常的做法就是引入Mediator(中间层,也有翻译成中介者),在SOA中,这个中间层通常指的就是ESB(企业服务总线)。

     

    四:计算模块

        计算模块接口的设计与实现过程。就是设计代码的组织方式,具体包括:有几个类,几个函数,他们之间的关系,画出关键函数流程图关键的算法(不展示源代码),以及独到之处。(4')

     

    (一) 整体上,模块划分如图:

    (二)在project5项目/src下建立Commandl.java和Answer.java等文件。

    类有七个,分别为Commandl类,Calculate类,Expression类,Judge类,Answer类,Change类和WriteReader 类。

     

    Commandl:GUI首界面,选择生成怎样的算式,运算式数量,数字的范围,操作符个数以及有无乘除法等。

    Calculate类,Calculate1类:分别是生成GUI界面的运行结果和命令窗口的算术表达式。

    Expression类:生成GUI界面的算术表达式

    Judge类:判断结果是否正确。

    Answer类:小学生四则运算答题和计时界面(Thread类),反馈答题对错情况的界面。

    Change类:

    WriteToFile 类读取和写入用户使用四则运算的计算结果,还包含用户答题正确数量。

    java.awt.Frame类,是顶级窗口,可以显示标题,重置大小。当frame被关闭的时候会产生windowevent事件,Frame无法直接监听键盘的输入事件。

    java.awt.FlowLayout类,是流式布局管理器。

    java.awt.TextArea类,是一个文本区组件。

     

    GUI组件继承关系图如下:

     

     

    (三)涉及重要函数和函数流程图及逻辑关系:

    1.random()函数,生成随机数

     1 Random random=new Random(); 2 int s=random.nextInt(op); //随机选择某个运算符 

    2.eval()函数,计算字符串内的运算式

     

    1 double result=0;
    2 try {
    3      result = Double.parseDouble(String.valueOf(engine.eval(ex)));//字符型变为整型
    4 } catch (ScriptException e) {
    5     e.printStackTrace();
    6 }

     3.createExp()函数,产生并返回计算表达式

     

     1 public String createExp() {
     2         
     3         char[] operator=new char[]{'+','-','*','/'};
     4         Random random=new Random(); 
     5         int[] number=new int[Four.jtf1Num+1]; 
     6         String ex=new String();
     7         for(int j=0;j<=Four.jtf1Num;j++){
     8             number[j]=random.nextInt(Four.jpfMNum-Four.jpfNum+1)+Four.jpfNum; //运算数
     9         }
    10         int q=0;
    11         for(int j=0;j<Four.jtf1Num;j++){
    12            int op=0;
    13            if(Four.jpf1Num!=0)
    14                op=4;    
    15            else
    16                op=2;
    17         int s=random.nextInt(op); //随机选择某个运算符
    18         while(s==q)   //至少两种运算符
    19             s=random.nextInt(op);
    20         q=s;                  
    21         ex+=String.valueOf(number[j])+String.valueOf(operator[s]);
    22         if(s==3){number[j+1]=decide(number[j],number[j+1],Four.jpfMNum,Four.jpfNum);}//避免出现小数
    23         }
    24         ex+=String.valueOf(number[Four.jtf1Num]);
    25         double result=0;
    26         try {
    27              result = Double.parseDouble(String.valueOf(engine.eval(ex)));//字符型变为整型
    28         } catch (ScriptException e) {
    29             e.printStackTrace();
    30         }
    31         
    32         if(Math.floor(result)==result&&result>0&&result<99999) {
    33             return ex;
    34         }else{
    35             return createExp();
    36         }
    37         
    38     }
    View Code

     4.trim()函数,返回调用字符串对象的一个副本,删除起始和结尾的空格

    1 Four.jtfNum = Integer.parseInt(this.jtf.getText().trim());//运算式个数
    2 Four.jpfNum = Integer.parseInt(this.jpf.getText().trim());//lower            
    3 Four.jpfMNum = Integer.parseInt(this.jpfM.getText().trim());//upper            
    4 Four.jtf1Num = Integer.parseInt(this.jtf1.getText().trim());//sumOfOperation
    5 Four.jpf1Num = Integer.parseInt(this.jpf1.getText().trim());//有无乘数法

     5.decide()函数,产生整数,防止出现分数

     1 private int decide(int x,int y,int max,int min){
     2         Random random=new Random();
     3         if(x%y!=0){
     4             y=random.nextInt(max-min+1)+min;
     5             return decide(x,y,max,min);
     6         }
     7         else{
     8             return y; 
     9         }
    10     }

     6.start()方法,thread类的方法,真正实现了多线程运行,无需等待。run()方法必须是public访问权限,返回值类型为void

     1 thread.start(); // 计数线程一直运行

    7.run()方法,thread类的方法,放有需要并行处理的代码,相当于普通方法的方式调用,程序顺序执行

     

    1 public void run() { 2 while (true) { 3 if (!stopped) { 4 long elapsed = System.currentTimeMillis() - programStart; 5 label.setText(format(elapsed)); 6 } 7 try { 8 sleep(1); // 1毫秒就更新1次 9 } catch (InterruptedException e) { 10 e.printStackTrace(); 11 System.exit(1); 12 } 13 } 14 }

    8.Commandl.java主界面,整体布局。

     

      1 public class Command extends JFrame {
      2     private static final long serialVersionUID = 1L;
      3     // 定义登录界面的组件
      4     JButton jb1, jb2, jb3 = null;
      5     JPanel jp1, jp2, jp3, jp4,jp5,jp6= null;
      6     JTextField jtf = null;
      7     JTextField jpf = null;
      8     
      9     JTextField jpfM = null;
     10     
     11     JTextField jtf1 = null;
     12     JTextField jpf1= null;
     13     
     14     JLabel jlb1, jlb2,jlb3, jlb4= null;
     15     ButtonGroup bg = null;
     16     static int exepresionNum = 0;
     17     
     18     static int exepresionRangeNum;
     19     
     20     static int jtfNum = 0;
     21     static int jpfNum = 0;
     22     
     23     static int jpfMNum = 0;
     24     
     25     static int jtf1Num = 1;
     26     static int jpf1Num = 0;
     27 
     28     public static void main(String[] args) {
     29         new Command();
     30     }
     31 
     32     // 构造函数
     33     public Command() {
     34         // 创建组件
     35         jb1 = new JButton("确认");
     36         jb2 = new JButton("刷新");
     37         jb3 = new JButton("退出");
     38         // 设置监听
     39         jb1.addActionListener(new ActionListener() {
     40 
     41             @Override
     42             public void actionPerformed(ActionEvent e) {
     43                 OK();
     44             }
     45         });
     46         jb2.addActionListener(new ActionListener() {
     47 
     48             @Override
     49             public void actionPerformed(ActionEvent e) {
     50                 clear(); 
     51             }
     52         });
     53         jb3.addActionListener(new ActionListener() {
     54 
     55             @Override
     56             public void actionPerformed(ActionEvent e) {
     57                 System.exit(0);
     58             }
     59         });
     60 
     61         jp1 = new JPanel();
     62         jp2 = new JPanel();
     63         jp3 = new JPanel();
     64         jp4 = new JPanel();
     65         jp5 = new JPanel();
     66         jp6 = new JPanel();
     67 
     68         jlb1 = new JLabel("生成题目个数:");
     69         jlb2 = new JLabel("题目数值范围:");
     70         jlb3 = new JLabel("操作符个数:");
     71         jlb4 = new JLabel("乘除法 0无1有:");
     72 
     73         jtf = new JTextField(10);
     74         jpf = new JTextField(4);
     75         
     76         jpfM = new JTextField(4);
     77         
     78         jtf1 = new JTextField(10);
     79         jpf1 = new JTextField(10);
     80         // 加入到JPanel中
     81         jp1.add(jlb1);
     82         jp1.add(jtf);
     83 
     84         jp2.add(jlb2);//jpfM是最大值
     85         jp2.add(jpf);
     86         jp2.add(jpfM);
     87         
     88         
     89         jp5.add(jlb3);
     90         jp5.add(jtf1);
     91 
     92         jp6.add(jlb4);
     93         jp6.add(jpf1);
     94 
     95         jp4.add(jb1);
     96         jp4.add(jb2);
     97         jp4.add(jb3);
     98         // 加入JFrame中
     99         this.add(jp1);
    100         this.add(jp2);
    101         this.add(jp5);
    102         this.add(jp6);
    103         this.add(jp3);
    104         this.add(jp4);
    105         
    106 
    107         // 设置布局管理器
    108         jlb1.setFont(new java.awt.Font("Dialog", 0, 20));
    109         jlb2.setFont(new java.awt.Font("Dialog", 0, 20));
    110         jlb3.setFont(new java.awt.Font("Dialog", 0, 20));
    111         jlb4.setFont(new java.awt.Font("Dialog", 0, 20));
    112         jtf.setFont(new Font("宋体", Font.PLAIN, 20));
    113         jpf.setFont(new Font("宋体", Font.PLAIN, 20));
    114         
    115         jpfM.setFont(new Font("宋体", Font.PLAIN, 20));
    116         
    117         jtf1.setFont(new Font("宋体", Font.PLAIN, 20));
    118         jpf1.setFont(new Font("宋体", Font.PLAIN, 20));
    119         Font f = new Font("华文行楷", Font.BOLD, 20);
    120         jb1.setFont(f);
    121         jb2.setFont(f);
    122         jb3.setFont(f);
    123         this.setLayout(new GridLayout(4, 1));
    124         // 给窗口设置标题
    125         this.setTitle("小学生四则运算界面");
    126         // 设置窗体大小
    127         this.setSize(600, 300);
    128         // 设置窗体初始位置
    129         this.setLocation(700, 330);
    130         // 设置当关闭窗口时,保证JVM也退出
    131         this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    132         // 显示窗体
    133         this.setVisible(true);
    134         this.setResizable(true);
    135     }

     

     

     

    (五)项目/src下Command.java类:

      读取命令行的参数,命令窗口运行。具体实现如图:

     

     

       打印在result.txt文件中如下:

     

    五: 性能分析

      计算模块接口部分的性能改进。记录在改进计算模块性能上所花费的时间,描述你改进的思路,并展示一张性能分析图,并展示你程序中消耗最大的函数。(4')

       

      通过参数传值,类间调用等实现模块的对接(主要是Commandl类和Expression类)。参考Frofile教程,学习软件用了约三小时,内存消耗如图:分析可知相对稳定。


     

      最初由项目的Command。java右键Profile As,进入性能分析,其次打开JVM虚拟机(可以用教程的密码破解Frofile软件)。然后进入Live memory,最初消耗变化如图:

     

     

      等待两分钟后,出现红色绿色并存现象:

     

       性能分析排查后,发现代码还有不足,进行优化处理。花费了约一小时,代码优化改进了,并且把占用内存的四则运算GUI小程序关闭,IO输入流关闭,性能如图明显提高。

     

    六:单元测试

       计算模块部分单元测试展示。展示出项目部分单元测试代码,并说明测试的函数,构造测试数据的思路。并将单元测试得到的测试覆盖率截图,发表在博客中。只需要测试命令行部分,且该部分覆盖率到90%以上,否则单元测试部分视作无效。(6')

     

      测试结果如下:

     

    七:异常处理

      计算模块部分异常处理说明。在博客中详细介绍每种异常的设计目标。每种异常都要选择一个单元测试样例发布在博客中,并指明错误对应的场景。(5')

      (一)Java标准裤内建了一些通用的异常,这些类以Throwable为顶层父类:

     

    (二)判断参数范围是否符合题意

    1 public static boolean scope(int num){
    2         if(num<=0||num>=10001)
    3             return false;
    4         else{
    5             return true;
    6         }
    7 
    8 }

    (三)判断参数的格式是否正确

     

    1 try {
    2        num = Integer.parseInt(args[++i]);
    3   } catch (NumberFormatException e) {
    4        e.printStackTrace();
    5        return;
    6   }

     

     

    八:界面设计

      界面模块的详细设计过程。在博客中详细介绍界面模块是如何设计的,并写一些必要的代码说明解释实现过程。(5')

      

     第一个界面是选题要求,输入后进入答题模块:

     

      

      第二个界面是答题计时界面,输入答案后进入判断界面:

     

      

      第三个界面是反馈界面,判断有三种,分别是输入为空,输入答案正确,输入答案错误,还有记忆正确数量的功能(WriteReader类):

     

       输入为空:

     

      输入答案错误:

     

      输入答案正确:

     

    九:模块对接

      界面模块与计算模块的对接。详细地描述UI模块的设计与两个模块的对接,并在博客中截图实现的功能。(4')

      

      界面模块主要是Commandl.java,Answer.java,计算模块主要是Expression.java。通过参数传值,类间调用等实现模块的对接(主要是Commandl类和Expression类)。

     

    十:结对过程

      结对的过程和结对照片。(1')

     

      我的队友是陈双林同学,照片是我们在调一个大Bug:ReallyAnawer提示为NULL,经过约6小时的讨论分析,发现错误是少写了一句代码answerGet(exe),并写上解决了问题。

     

     

     

    十一:结对编程

      说明结对编程的优点和缺点。同时指出结对的每一个人的优点和缺点在哪里 (要列出至少三个优点和一个缺点)。(5')

     

     结对编程整体有如下的好处:

    (1)在开发层次,结对编程能提供更好的设计质量和代码质量,两人合作能有更强的解决问题的能力。

    (2)对开发人员自身来说,结对工作能带来更多的信心,高质量的产出能带来更高的满足感。

    (3)在心理上,  当有另一个人在你身边和你紧密配合, 做同样一件事情的时候,  你不好意思开小差, 也不好意思糊弄。

    (4)在企业管理层次上,结对能更有效地交流,相互学习和传递经验,能更好地处理人员流动。因为一个人的知识已经被其他人共享。

     (5) 结对编程的过程也是一个互相督促的过程,每个人的一举一动都在别人的视线之内,所有的想法都要受到对方的评价。由于这种督促的压力,使得程序员更认真地工作。

     (6) 程中驾驶员和领航员的互换可以让程序员轮流工作,从而避免出现过度思考而导致观察力和判断力下降。

     

     结对编程对我和队友具体有如下的好处:遇到问题可以更好更快的解决,而且对一些细节可以进行分工,加快我们的实现进程。总之,如果运用得当,结对编程能得到更高的投入产出比(Return of Investment)。

     

    结对编程有如下的缺点:

    (1)并不是所有的项目都适合结对编程。

       例如:1)处于探索阶段的项目,需要深入地研究,在这种情况下,一个人长时间的独立钻研是有必要的。

         2)在做后期维护的时候,如果维护的技术含量不高,只需要做有效的复审即可,不必拘泥于形式,硬拉一个人来结对唱二人转。

         3)处于探索阶段的项目,需要深入地研究,在这种情况下,一个人长时间的独立钻研是有必要的。

        4)在做后期维护的时候,如果维护的技术含量不高,只需要做有效的复审即可,不必拘泥于形式,硬拉一个人来结对唱二人转。

         5)如果验证测试需要运行很长时间,那么两个人在那里等待结果是有点浪费时间。

        6)如果团队的人员要在多个项目中工作,不能充分保证足够的结对编程时间,那么成员要经常处于等待的状态,反而影响效率。

        7)关键是如何最大限度地发挥“领航员”的作用,如果用处不大,也就无需结对。

     

     结对编程对我和队友具体有如下的缺点:我们在结对的过程中彼此的想法会产生分歧,这有时也会浪费许多时间来达成共识。

     

    采用汉堡包的方法对队友和自己评价:

    卫小琼:优点:类间调用关系清晰;Debag能力不错,逻辑辨析能力出色;同学关系好,解决不了的问题能找到人帮忙

          缺点:太过于追求细节,项目经验缺乏。

    陈双林:优点:脾气好,能坚持,有上进心。

            缺点:基础薄弱,编码能力弱。

     

    十二:PSP记录

     

     

     

    任务内容

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

    实际完成需要的时间

    (min)

    Planning

    计划

    30

    40

    · Estimate

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

    10

    10

    Development

    开发

    1250

    2375

    ·Analysis

    ·需求分析 (含有学习新技术)

    300

    400

    ·Design Spec

    ·生成设计文档

    20

    30

    ·Design Review

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

    10

    20

    ·Coding Standard

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

    15

    20

    ·Design

    ·具体设计

    30

    60

    ·Coding

    ·具体编码

    600

    1500

    ·Code Review

    ·代码复审

    30

    45

    ·Test

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

    200

    300

    Modular

    模块

    600

    750

    ·Computing module 计算模块 400 450
    ·Timing module 计时模块 200 300

    Reporting

    报告

    490

    850

    ·Test Report

    ·测试报告

    420

    780

    ·Size Measurement

    ·计算工作量

    40

    40

    ·Postmortem & Process Improvement Plan

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

    30

    30

     

     尾言:

    在结对项目中,长时间的交流和编写使我们学到很多,成长很快,很幸运有这样一次锻炼自己的机会。

    博客1  https://blog.csdn.net/zhoufoxcn/article/details/1700018

    博客2 Java项目测试覆盖率: https://www.cnblogs.com/happyzm/p/6530384.html

    博客3 JProfiler做效能分析:https://www.cnblogs.com/AmilyWilly/p/7272160.html

    雪儿言
  • 相关阅读:
    改了信仰,”U秒英伟达,卡秒英特尔“
    我的技嘉GTX970G1Gaming
    入手笨球BL2710PE
    买显示器的各种纠结
    [转]关于液晶显示器的6bit面板、8bit面板及E-IPS
    Windows API中的数据结构
    C语言中函数参数传递
    修改powershell字体
    [知乎]学了 Python 之后,再学 Java 是不是会更容易?
    Windows10上用命令行,奢侈的享受?
  • 原文地址:https://www.cnblogs.com/weixq351/p/8746814.html
Copyright © 2020-2023  润新知