首页 > 技术文章 > 结对作业(2016012066)

thomaskang 原文

1、代码:https://git.coding.net/Thomaskang/Cooperativeproject.git

 web测试url: http://119.29.189.249/sizeyunsuan/first.jsp 

再来张图片缓解一些压力

2、预估PSP耗时:

   

                                                                    

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

Planning

计划

30

· Estimate

· 估计这个任务需要多少时间

30

Development

开发

990 

· Analysis

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

60

· Design Spec

· 生成设计文档

40

· Design Review

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

30

· Coding Standard

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

20

· Design

· 具体设计

60

· Coding

· 具体编码

600

· Code Review

· 代码复审

60

· Test

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

120

Reporting

报告

110 

· Test Report

· 测试报告

60

· Size Measurement

· 计算工作量

10

· Postmortem & Process Improvement Plan

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

40

 

  3、首先我再看了一下信息隐藏、面向接口编程、松耦合(Information Hiding, Interface Design, Loose Coupling)这三者的概念。然后相应的谈在理解了这三点概念对我编码的思想引导与好处。

  老实说,在看到这三个名词前都点懵的,但知道了它的意思过后发现它们早已进入我们以前编码当中了。

  信息隐藏:

  某种方面来说,它就是我们常常讲的对象的封装(encapsulation)与模块化(modularity),把一个类把复杂的、敏感的、一旦被外界捕获可能会引起不良后果的内容封装在自身内部,这个类以外的代码得不到此类信息(通过反射等手段可能对得到),以提高程序的安全性与健壮性。

  针对这一点,我们在设计我们代码的时候就准备好把每一个计算和其他模块进行类的封装。用总体的类来进行调用,由此达到信息隐藏的作用。

  面向接口编程:

  面向接口编程,是在面向对象之后我们要进一步做的。因为我们在做结对项目。在和我的小伙伴搭档的时候,我们也考虑到了这一概念的运用。设置一个总的接口,去掉用各个类。在树立结口的概念之后,虽然我们在初期并不需要很清楚整个测试程序的调度工作原理与架构,但是只要我们专注于实现ISchedule的功能,就能够达到调度的目的。我们在做每一个类的时候,完全不必要想这个类与其他类的关系,只用完成这一个模块,只用考虑一个大的接口。在最后的Command接口的时候做统一的调度。

  松耦合:

  它其实是前面两种方法的结合方式。在制作每个隐藏封装的类的时候,我们不去想别的类,单纯实现一个块的方法,产生随机数的类就只产生随机数,与其他的块保持一种很松的关系。

  以此保证了一个类出问题不会影响到另外一个类。

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

  首先,我思考“计算”的这个接口需要就是题目要求的五个参数所要实现的类与方法。以最后要结合的接口Command作为框架

  

  然后,去做这个接口需要调用的类的方法

  (1)实体类:一个产生随机数,两个产生计算符(计算符写两个,有乘除和没有)。传入最小值最大值。

  (2)拼接类:将随机数和计算符进行拼接,循环产生很多道题。传入题目数量。传入接口的o运算符个数参数。

  (3)括号类,给出的题加括号,给接口调用。

  (4)IO类,用来输出到result.txt。

  (5)总体类与接口:把各个类进行调用与完成他们的方法。传入是否乘除,是否括号来看调用哪些类的方法。

  算法的关键:主要就是拼接类和接口调用类的时候的条件判断,从前台传参过来参数转换啥了,总体来说很简单。没用啥高深的算法。

  独到之处:实现了松耦合,各个模块都能够单独使用。传入最大值和最小值限度哪里用的方法很巧妙,先考虑小于最大值,用随机数与最大值最小值查的关系来计算,最后判断与最小值的关系。

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

  首先,先拿出我们用JProfiler做的效能分析:

  首先是内存等等的分析:

  

  然后查看了record object:

      

  在一次次的runGC之后,我们找到了影响效能的两个包:IO 和String lang包

  

   然后我们针对性的想对io和lang包的应用改进。发现是很多导入的io和lang包没有用到。我们对其进行了删除。

   

   其次讲讲我们在效能分析之外对各个模块的优化改进和相关花费时间。

  (1)、实体类:多加了一个没有乘除的实体运算符类。时间没有啥。

  (2)、拼接类用的时间最多,写了两个for循环思考挺多,因为得考虑传参进去确定运算符的多少,还得排除一些可能的异常。

  (5)、括号类是写得最简单的,是硬加的括号。所以改没花太多时间,只是在哪儿加括号有纠结花了一些时间。最后也没有想到好的算法实现,因为是模块化,所以感觉也只能够硬加括号。

  (4)、IO类没有花费时间改,原本就是模块。

  (5)、接口拼接也花了很多时间,主要是最后优化处理异常的时候。

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

  运用juit进行测试,导入了juit包。

  思路就是,比如在需要数字地方传递的字符串就返回异常。还有添加一些除了题目要求的极限方法。

  测试代码是搭档写的,展示在这儿:

     

 

    

public class CommandTest {
    
    //测试输入的参数是否合法
    @Test()
    public void testParameter1Error1(){
        String ex ="-n";
        assertEquals(true,new Command().parameter1Error(ex));
    }
    @Test()
    public void testParameter1Error2(){
        String ex ="-z";
        assertEquals(false,new Command().parameter1Error(ex));
    }
    
    //测试输入的参数n是否合法
    @Test
    public void testScopeOfSumError1(){
        int num=-1;
        assertEquals(false, new Command().scopeOfSumError(num));
    }
    @Test
    public void testScopeOfSumError2(){
        int num=10;
        assertEquals(true, new Command().scopeOfSumError(num));
    }
    
    
    //测试输入的参数m是否合法
    @Test
    public void testScopeOfArgsMError1(){
        int scope_Lower=-1;
        int scope_Upper=1001;
        assertEquals(1, new Command().ScopeOfArgsMError(scope_Lower, scope_Upper));
    }
    @Test
    public void testScopeOfArgsMError2(){
        int scope_Lower=80;
        int scope_Upper=50;
        assertEquals(2, new Command().ScopeOfArgsMError(scope_Lower, scope_Upper));
    }
    @Test
    public void testScopeOfArgsMError3(){
        int scope_Lower=10;
        int scope_Upper=90;
        assertEquals(3, new Command().ScopeOfArgsMError(scope_Lower, scope_Upper));
    }
    
    //测试输入的参数o是否合法
    @Test 
    public void testSumOfOperationError1(){
        int sumOfOperation = 20;
        assertEquals(false, new Command().sumOfOperationError(sumOfOperation));
    } 
    @Test
    public void testSumOfOperationError2(){
        int sumOfOperation = 4;
        assertEquals(true, new Command().sumOfOperationError(sumOfOperation));
    }
}

 

 7、异常处理:

  先展示正确的打开方式:

  

  

  然后这是其中一个异常,随便输入字符异常的报错:

  

  其他题目不做截图,提供代码:

  关于题目数量异常处理:

    public static void scopeOfSumError(int num) throws Exception{
        if(num<=0||num>10000)
            throw new Exception("n输入范围有误,参数范围为 1 ~ 10000,请重新输入");
    }

  关于用户输入不在那五个参数的异常处理:

    public static void parameter1Error(String ex,int i)throws Exception{
        ArrayList<String> args = new ArrayList<String>(); 
        args.add("-n");
        args.add("-m");
        args.add("-o");
        args.add("-c");
        args.add("-b");
        if(!args.contains(ex)){
            throw new Exception("请输入正确的那几个参数");
        }
    }

  关于上下界的异常处理:

  

public static void ScopeOfArgsMError(int scope_Lower,int scope_Upper) throws Exception{
        if(scope_Lower<1||scope_Lower>100||scope_Upper<50||scope_Upper>1000)
            throw new Exception("m的输入范围有误, 下界范围为 1到100,上界范围为 50到1000");
        if(scope_Lower>=scope_Upper)
            throw new Exception("上界要大于下界");
    }

  关于运算符的异常处理:

  

public static void OperationError(int Operation)throws Exception{
        if(Operation<=0||Operation>10000)
            throw new Exception("o的输入有误,-o 范围为 1 到 10");
        
    }

 

8、界面模块的详细设计过程:
  我们用的是网页端来展示界面模块,所以主要是html,css,bootstrap样式库来实现的界面模块设计。
  模块分为三块:首页面,题目下载页面,做题页面
  首页面,链接进下载页面和做题页面,还打算加一个多用户登录,但发现后台可能得要数据库才能实现,又删掉了。

  
  题目下载页面:用户输入下载题目的各种限制参数,都是用的input,放在一个form表单里面。还有返回首页和直接做题的导航。标签和表单用bootstrap做的样式。

  

<form  class="wrap" action="servlet/ChuanServlet" method="post">
      <div class="form-inline" >
       <div class="form-group">
    <label for="exampleInputName2" >出题数目</label>
    <input  class="form-control" name="problem-number" placeholder="请输入">
      </div>
      </div>
      
      
      <div class="form-inline">
  <div class="form-group">
    <label for="exampleInputName2" >下限数值</label>
    <input type="text" class="form-control" name="down-number" placeholder="请输入">
  </div>
  <div class="form-group">
    <label for="exampleInputEmail2">上限数值</label>
    <input  class="form-control" name="up-number" placeholder="请输入">
  </div>
  </div>
  
  
  <div class="form-inline">
       <div class="form-group">
    <label for="exampleInputName2">运算符数</label>
    <input  class="form-control" name="operator-number" placeholder="请输入">
      </div>
      </div>
  
  
      
      <div class="form-inline">
           <label for="exampleInputName2">是否乘除</label>
      <select class="form-control" name="select-chengchu">
  <option>yes</option>
  <option>no</option>
</select>

<label for="exampleInputName2" >是否括号</label>
      <select class="form-control" name="select-kuohao">
  <option>yes</option>
  <option>no</option>
</select>
</div>
 
  
    <button type="submit" class="btn btn-default">开始打印到本地txt</button>
</form>


  做题页面:包括一个导航,黑板做题,上传题目做题,点击next按钮。

 

<div class="tiban">
                <div class="timu-last">
                <img   class="heiban" src="img/heiban.jpg" />
                
                    <span class="jieguo1" id="chuanjieguo">39+45+34+67+33+45</span>
                <!--<textarea rows="3"></textarea>-->
                </div>
                <div class="jieguo-last">
                <img  class="daan-img" src="img/daan.jpg" />
                <input class="jieguo" id="inputnumver"/><button type="button" class="btn btn-danger" id="next" onclick="loadXMLDoc()">next</button>
            </div>
                <div class="tip">
                <span>答题时间:</span><span>20分钟</span>
                &nbsp;&nbsp;&nbsp;&nbsp;
                <span>答对个数:</span><span>20个</span>
                <form>
                <input id="photoCover" class="input-large"  placeholder="上传题目答题" type="file" style="height:30px;">  
                </form>
                </div>    

 

 

9、用的web端,所以我们前后端的连接与数据传输主要是通过前台js和后台servlet。用mvc模式,servlet做控制器。
  题目下载页面:form调用表单传递到servlet,servlet调用后台的最终总结接口,接口再调用各种相关的类,实现题目的下载打印到本地。
  做题页面:这是耗时最多的一个页面。也是前后台交接最复杂的页面。页面包含开始和结束答题,然后前台js用函数实现计时。
  其次,前台通过每次输入完计算结果后点击next按钮,用ajax在不刷新页面情况下把答案和下一个题目的请求传递到后台,
后台在通过传值到ajax实现题目的切换。后台把前台传的答案与原本题目的计算结果进行比较,计算答对题目的个数。并把个数传递到前台显示。对错传递到前台改变小球的颜色,对了是绿色,错了是红色。

  
  还有,前台用户除了可以要求系统直接出题,还可以自己上传题目做题。题目传递到后台,后台用IO输入流一行一行的读取,再保持单个的传递到前台。

 10、结对过程

  由于时间关系,我们双方在项目前期几乎都是独立进行编程,对方主要负责后端,我主要负责前台和servlet交互,遗憾是前期在一起对项目进行规划和设计的时间很少。清明节放假期间我们开始进入一有时间就一起写代码的状态,共同分析代码,实现前后端交互,并不断改进代码。在结对编程的过程中,我发现对方思维方式比较独特,有很多新奇的想法,而我思路比较局限,缺乏创新。

  

  结对编程的优点

  相互督促,加快进度

  处理问题的速度快,分工合作,每人负责自己的部分,效率高。

  从对方身上可以看到独特的思维方式,值得学习

  结对编程的缺点:

  分工容易出现失衡 

  代码风格不一致

  有的时候会因为某个需求而等待对方,减慢速度。

  要花费时间向对方解释代码

 

 11、结对双方的优缺点

   对方优点:(1)很容易沟通,待人亲切随和(2)代码快,细心,有责任心(3)思维独特,勇于挑战困难

   对方缺点:代码格式不是很规范

 12、PSP

  

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

30

40

· Estimate

· 估计这个任务需要多少时间

30

40

Development

开发

990 

1390 

· Analysis

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

60

70

· Design Spec

· 生成设计文档

40

60

· Design Review

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

30

40

· Coding Standard

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

20

20

· Design

· 具体设计

60

80

· Coding

· 具体编码

600

820

· Code Review

· 代码复审

60

120

· Test

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

120

180

Reporting

报告

110 

195 

· Test Report

· 测试报告

60

120

· Size Measurement

· 计算工作量

10

15

· Postmortem & Process Improvement Plan

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

40

60 

 

推荐阅读