Java实验报告二

北京电子科技学院(BESTI)

              

课程:Java程序设计实验   班级:1353  姓名:符运锦  学号:20135323

成绩:                           指导教师:娄嘉鹏      实验日期:2015.5.8

  实验密级:无            预习程度:                   实验时间:15:30~18:00

仪器组次:  23                    必修/选修: 选修                  实验序号:2

实验名称:Java面向对象程序设计                                       

实验目的与要求:                                            

目的:1. 初步掌握单元测试和TDD

                                    2. 理解并掌握面向对象三要素:封装、继承、多态

3. 初步掌握UML建模

  4. 熟悉S.O.L.I.D原则

5. 了解设计模式

要求:

                                                                                                           1.没有Linux基础的同学建议先学习《Linux基础入门(新版》《Vim编辑器》 课程

                                                                                                         2.完成实验、撰写实验报告,实验报告以博客方式发表在博客园,注意实验报告重点是运行结果,遇到的问题(工具查找,安装,使                                                                                                                 用,程序的编辑,调试,运行等)、解决办法(空洞的方法如“查网络”、“问同学”、“看书”等一律得0分)以及分析(从中可以得                                                                                                                     到什么启示,有什么收获,教训等)。报告可以参考范飞龙老师的指导

                                                                                                                 3. 严禁抄袭,有该行为者实验成绩归零,并附加其他惩罚措施。

                             

                                

 

名称

型号

数量

PC

SONY 

1

虚拟机

实验楼

1

 

实验内容、步骤与体会(附纸):

(一)单元测试

(1) 三种代码

编程是智力活动,不是打字,编程前要把干什么、如何干想清楚才能把程序写对、写好。与目前不少同学一说编程就打开编辑器写代码不同,我希望同学们养成一个习惯,当你们想用程序解决问题时,要会写三种码:

  • 伪代码
  • 产品代码
  • 测试代码

我们先写伪代码,伪代码可以用汉语写,推荐大家用英语写,伪代码与具体编程语言无关,不要写与具体编程语言语法相关的语句(如用malloc分配内存,这样只能用C语言编程了),伪代码从意图层面来解决问题,最终,伪代码产品代码最自然的、最好的注释。针对上面的问题,我们可以通过伪代码这样解决:

百分制转五分制: 如果成绩小于60,转成“不及格”

                       如果成绩在60与70之间,转成“及格”

        如果成绩在70与80之间,转成“中等”

        如果成绩在80与90之间,转成“良好”

        如果成绩在90与100之间,转成“优秀”

        其他,转成“错误”

有了伪代码,我们用特定编程语言翻译一下,就是可用的产品代码了,当然,我们在这要选用Java,小菜一碟了,翻译好的MyUtil.java如下:

这里我们设计了一个测试用例(Test Case)测试用例是为某个特殊目标而编制的一组测试输入、执行条件以及预期结果,以便测试某个程序路径或核实是否满足某个特定需求。这里我们的测试输入是“50”,预期结果是“不及格”。在Eclipse中运行结果如下,测试结果符合预期:

只有一组输入的测试是不充分的,我们把一般情况都测试一下,代码如下:

我们不能只测试正常情况,下面看看异常情况如何,比如输入为负分或大于100的成绩,代码如下:

运行程序发现负分时与期望不一致,终于找到了一个bug,原因是判断不及格时没有要求成绩大于零。我们修改MyUtil.java,增加对负分的判断,代码如下:

测试够了吗?还不够,一般代码在边界处最容易出错,我们还没有测试边界情况,我们对输入为“0,60,70,80,90,100”这些边界情况进行测试的代码如下:

 我们发现边界情况中输入100时有一个Bug。我们修改MyUtil.java,把判断优秀的条件中包含输入为100的情况,代码如下:

                                                              

  这时测试都符合预期了,我们把MyUtil.java提供给别人使用时,心里比较有底气了。那如何保证单元测度是充分的呢?我们的一般要求是测试代码要比产品代码多。如何写测试,《单元测试之道》提出了Right-BICEP的方法,大家可以参考一下。
软件是由多人合作完成的,不同人员的工作相互有依赖关系。软件的很多错误都来源于程序员对模块功能的误解、疏忽或不了解模块的变化。如何能让自己负责的模块功能定义尽量明确,模块内部的改变不会影响其他模块,而且模块的质量能得到稳定的、量化的保证?单元测试就是一个很有效的解决方案。

(2) TDD(Test Driven Devlopment, 测试驱动开发)

TDD的一般步骤如下:

  • 明确当前要完成的功能,记录成一个测试列表
  • 快速完成编写针对此功能的测试用例
  • 测试代码编译不通过(没产品代码呢)
  • 编写产品代码
  • 测试通过
  • 对代码进行重构,并保证测试通过(重构下次实验练习)
  • 循环完成所有功能的开发

我们在TDDDemo项目中,把鼠标放到项目名TDDDemo上,单击右键,在弹出的菜单中选定New->Source Folder新建一个测试目录test。

我们把鼠标放到test目录上,单击右键,在弹出的菜单中选定New->JUnit Test Case新建一个测试用例类MyUtilTest,如下图:

我们增加第一个测试用例testNormal,注意测试用例前一定要有注解@Test,测试用例方法名任意,输入以下代码:

 

 

测试结果出现了一个红条(red bar),说明测试没通过,红条上面汇总了测试情况,运行了一个测试,没有错误,一个测试没通过。下面原因说的也很清楚:测试代码第十行传入55时,期望结果是“不及格”,代码返回了“错误”,修改MyUtil.Java吧,输入以下代码:

试结果出现了一个绿条(green bar),说明测试通过了。TDD的目标是"Clean Code That Works",TDD的slogan是"Keep the bar green, to Keep the code clean"

TDD的编码节奏是:

  • 增加测试代码,JUnit出现红条
  • 修改产品代码
  • JUnit出现绿条,任务完成

我们增加一个测试异常情况的用例testException,我们增加一个测试边界情况的用例testBoundary

 

二)面向对象三要素

(1)抽象

抽象一词的本意是指人在认识思维活动中对事物表象因素的舍弃和对本质因素的抽取。抽象是人类认识复杂事物和现象时经常使用的思维工具,抽象思维能力在程序设计中非常重要,"去粗取精、化繁为简、由表及里、异中求同"的抽象能力很大程度上决定了程序员的程序设计能力。
抽象就是抽出事物的本质特征而暂时不考虑他们的细节。对于复杂系统问题人们借助分层次抽象的方法进行问题求解;在抽象的最高层,可以使用问题环境的语言,以概括的方式叙述问题的解。在抽象的较低层,则采用过程化的方式进行描述。在描述问题解时,使用面向问题和面向实现的术语。
程序设计中,抽象包括两个方面,一是过程抽象,二是数据抽象。

(2)封装、继承与多态

面向对象(Object-Oriented)的三要素包括:封装、继承、多态。面向对象的思想涉及到软件开发的各个方面,如面向对象分析(OOA)、面向对象设计(OOD)、面向对象编程实现(OOP)。OOA根据抽象关键的问题域来分解系统,关注是什么(what)。OOD是一种提供符号设计系统的面向对象的实现过程,用非常接近问题域术语的方法把系统构造成“现实世界”的对象,关注怎么做(how),通过模型来实现功能规范。OOP则在设计的基础上用编程语言(如Java)编码。贯穿OOA、OOD和OOP的主线正是抽象。
OOD中建模会用图形化的建模语言UML(Unified Modeling Language),UML是一种通用的建模语言,我们实验中使用umbrello进行建模,Windows中推荐大家使用 StarUML

过程抽象的结果是函数,数据抽象的结果是抽象数据类型(Abstract Data Type,ADT),类可以作具有继承和多态机制的ADT。数据抽象才是OOP的核心和起源。

OO三要素的第一个要素是封装,封装就是将数据与相关行为包装在一起以实现信息就隐藏。

 

 

 

  • +表示public
  • #表示 protected
  • -表示 private

(三)设计模式初步

(1)S.O.L.I.D原则

面向对象三要素是“封装、继承、多态”,任何面向对象编程语言都会在语法上支持这三要素。如何借助抽象思维用好三要素特别是多态还是非常困难的,S.O.L.I.D类设计原则是一个很好的指导:

 

  • SRP(Single Responsibility Principle,单一职责原则)
  • 决不要有一个以上的理由修改一个类
  • OCP(Open-Closed Principle,开放-封闭原则):
  • 软件实体(类,模块,函数等)应该对扩充开放,对修改封闭。
  • LSP(Liskov Substitusion Principle,Liskov替换原则)
  • 子类必须可以被其基类所代,使用指向基类的指针或引用的函数,必须能够在不知道具体派生类对象类型的情况下使用它
  • ISP(Interface Segregation Principle,接口分离原则)
  • 客户不应该依赖他们并未使用的接口
  • DIP(Dependency Inversion Principle,依赖倒置原则)
  • 高层模块不应该依赖于低层模块。二者都应该依赖于抽象,抽象不应该依赖于细节。细节应该依赖于抽象
    • (2)模式与设计模式

    • 模式是某外在环境(Context) 下﹐对特定问题(Problem)的惯用解决之道(Solution)。模式必须使得问题明晰,阐明为什么用它来求解问题,以及在什么情况下有用,什么情况下不能起作用,每个模式因其重复性从而可被复用,本身有自己的名字,有可传授性,能移植到不同情景下。模式可以看作对一个问题可复用的专家级解决方法。 计算机科学中有很多模式:

      • GRASP模式
      • 分析模式
      • 软件体系结构模式
      • 设计模式:创建型,结构型,行为型
      • 管理模式: The Manager Pool 实现模式
      • 界面设计交互模式

      这里面最重要的是设计模式,在面向对象中设计模式的地位可以和面向过程编程中的数据结构的地位相当。

    • (3)设计模式实示例

      设计模式(design pattern)提供一个用于细化软件系统的子系统或组件,或它们之间的关系图,它描述通信组件的公共再现结构,通信组件可以解决特定语境中的一个设计问题。 
    • (四)练习

      • 1使用TDD的方式设计关实现复数类Complex。

      •  

          • 伪代码:
          • 1.复数的实部为0,虚部为0
          • 2.复数的实部为0,虚部为对应数
          • 3.复数的实部为对应数,实部为0
          • 4.两参数分别为实部与虚部
          • 5.实现两复数的加法、减法、乘法。
          • 测试代码:
          • public class ComplexText
            {
            public static void main(String[] args)
            {
            Complex c=new Complex();
            Complex c1=new Complex(4,5);
            Complex c2=new Complex(6,7);
            c1.Print();
            c2.Print();
            System.out.println("这两复数和为:");
            System.out.println((c.jia(c1, c2).a+"+"+c.jia(c1, c2).b+"i").toString());
            System.out.println("这两复数差为:");
            System.out.println(c.jian(c1, c2).a+"+"+c.jian(c1, c2).b+"i");
            System.out.println("这两复数乘积为:");
            System.out.println(c.cheng(c1, c2).a+"+"+c.cheng(c1,c2).b+"i");

            }
            }

          • 产品代码:
            • public class Complex
              {
              double a,b;
              Complex()
              {
              this.a=0;
              this.b=0;
              }
              Complex(double a)
              {
              this.a=a;
              this.b=0;
              }
              Complex(double a,double b)
              {
              this.a=a;
              this.b=b;
              }
              Complex jia(Complex p1,Complex p2)
              {
              Complex p =new Complex(p1.a+p2.a,p1.b+p2.b);
              return p;
              }
              Complex jian(Complex p1,Complex p2)
              {
              Complex p =new Complex(p1.a-p2.a,p1.b-p2.b);
              return p;
              }
              Complex cheng(Complex p1,Complex p2)
              {
              Complex p = new Complex(p1.a*p2.a-p1.b*p2.b,p1.b*p2.a+p1.a*p2.a);
              return p;
              }void Print() 

            • {
              System.out.println("复数的值为:");
              if(this.b!=0)
              System.out.println(this.a+"+"+this.b+"i");
              else System.out.println(this.a);
              }


              }

            • 测试结果:
            •  

              • 2.统计自己的PSP(Personal Software Process)时间
              • 步骤

                耗时

                百分比

                需求分析

                      10  11.1%

                设计

                     15 16.7% 

                代码实现

                     50 55.6% 

                测试

                     10  11.1% 

                分析总结

                      5 5.6% 
              • 3.总结单元测试的好处
              • ①、更加明确开发的目的,避免出现重复或者过多冗长的工作,提升开发者的工作效率。
              • ②、代码更加清晰明确,模块化更加清晰。当代码出现问题时,更加容易进行维护和修改。
              • ③、在产品代码内部,各个类之间相互独立,互不影响,可以保证代码的独立性并且方便进行再次添加或减少。
              • ④、将产品代码和测试代码分开,更加方便使用者理解。
              • 4.遇到的问题
              • ①、自己的机子无法运行umbrello,之后从老师那里拷贝进了带了umbrello的虚拟机。
              • ②、运行umbrello时,抽象类无法运行,之后反复查看实验后才发现忘记去掉public only选项。
              • ③、实验楼的环境中无法使用中文输入,之后将中文输入转换成对应的英文输入。
              • ④、进行COMPLEX类练习时,运行RUN AS后无法出现对应结果,发现是测试用的类名与对应的文件名不一致,下次应尽量减法犯此类低级错误。
              • 5.实验体会与感想:
              • 这是本学期的第二次JAVA实验,相比于第一次实验,我们操作更加成熟的同时实验难度也加大了。对于此次的实验,我理解了何为UML图,并且在实验后理解其与代码是可以相互转换的。最后一个实验SOLID原则,更是让我对于TDD原则有了进一步的理解,让我养成良好的编程习惯有重要的作用。并且,在日后的实验中应更加注重自己思维方面的训练等等。
posted @ 2015-05-07 02:27  20135323符运锦  阅读(223)  评论(0编辑  收藏  举报