zoukankan      html  css  js  c++  java
  • 20145201 实验二 Java面向对象程序设计

    20145201实验二 Java面向对象程序设计

    初步掌握单元测试和TDD

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

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

    我们通过一个例子说明如何写这三种代码。

    • 伪代码
       百分制转五分制:
       如果成绩小于60,转成“不及格”
       如果成绩在60与70之间,转成“及格”
       如果成绩在70与80之间,转成“中等”
       如果成绩在80与90之间,转成“良好”
       如果成绩在90与100之间,转成“优秀”
       其他,转成“错误”
    
    • 产品代码
    public class MyUtil{
        public static String percentage2fivegrade(int grade){
            //如果成绩小于60,转成“不及格”
            if (grade < 60)
                return "不及格";
                //如果成绩在60与70之间,转成“及格”
            else if (grade < 70)
                return "及格";
                //如果成绩在70与80之间,转成“中等”
            else if (grade < 80)
                return "中等";
                //如果成绩在80与90之间,转成“良好”
            else if (grade < 90)
                return "良好";
                //如果成绩在90与100之间,转成“优秀”
            else if (grade < 100)
                return "优秀";
                //其他,转成“错误”
            else
                return "错误";
        }
    }
    
    • 测试代码

    1、用50分测试时:

    public class MyUtilTest {
     public static void main(String[] args) {
        // 百分制成绩是50时应该返回五级制的“不及格”
        if(MyUtil.percentage2fivegrade(50) != "不及格")
            System.out.println("test failed!");
        else
            System.out.println("test passed!");
        }
    }
    

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

     public class MyUtilTest {
        public static void main(String[] args) {
            //测试正常情况
            if(MyUtil.percentage2fivegrade(55) != "不及格")
                System.out.println("test failed!");
            else if(MyUtil.percentage2fivegrade(65) != "及格")
                System.out.println("test failed!");
            else if(MyUtil.percentage2fivegrade(75) != "中等")
                System.out.println("test failed!");
            else if(MyUtil.percentage2fivegrade(85) != "良好")
                System.out.println("test failed!");
            else if(MyUtil.percentage2fivegrade(95) != "优秀")
                System.out.println("test failed!");
            else 
                System.out.println("test passed!");
        }
    }
    

    在Eclipse中运行结果如下,测试结果符合预期:

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

     public class MyUtilTest {
        public static void main(String[] args) {
            //测试出错情况
            if(MyUtil.percentage2fivegrade(-10) != "错误")
                System.out.println("test failed 1!");
            else if(MyUtil.percentage2fivegrade(115) != "错误")
                System.out.println("test failed 2!");
            else 
                System.out.println("test passed!");
        }
    }
    

    增加对负分的判断,代码如下:

    public class MyUtil{
       public static String percentage2fivegrade(int grade){
           //如果成绩小于0,转成“错误”
           if ((grade < 0))
               return "错误";
           //如果成绩小于60,转成“不及格”
           else if (grade < 60)
               return "不及格";
           //如果成绩在60与70之间,转成“及格”
           else if (grade < 70)
               return "及格";
           //如果成绩在70与80之间,转成“中等”
           else if (grade < 80)
               return "中等";
           //如果成绩在80与90之间,转成“良好”
           else if (grade < 90)
               return "良好";
           //如果成绩在90与100之间,转成“优秀”
           else if (grade < 100)
               return "优秀";
           //如果成绩大于100,转成“错误”
           else
               return "错误";
       }
    }
    

    再次运行测试,测试结果符合预期,如下图所示:

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

    public class MyUtilTest {
        public static void main(String[] args) {
            //测试边界情况
            if(MyUtil.percentage2fivegrade(0) != "不及格")
                System.out.println("test failed 1!");
            else if(MyUtil.percentage2fivegrade(60) != "及格")
                System.out.println("test failed 2!");
            else if(MyUtil.percentage2fivegrade(70) != "中等")
                System.out.println("test failed 3!");
            else if(MyUtil.percentage2fivegrade(80) != "良好")
                System.out.println("test failed 4!");
            else if(MyUtil.percentage2fivegrade(90) != "优秀")
                System.out.println("test failed 5!");
            else if(MyUtil.percentage2fivegrade(100) != "优秀")
                System.out.println("test failed 6!");
            else 
                System.out.println("test passed!"); 
        }
    }
    

    测试结果如下:

    优秀成绩包含100时:

    TDD

    先写测试代码,然后再写产品代码的开发方法叫“测试驱动开发”(TDD)。
    TDD的一般步骤如下:

    1、明确当前要完成的功能,记录成一个测试列表

    2、快速完成编写针对此功能的测试用例

    3、测试代码编译不通过(没产品代码呢)

    4、编写产品代码

    5、测试通过

    6、对代码进行重构,并保证测试通过(重构下次实验练习)

    7、循环完成所有功能的开发

    TDD的编码节奏是:

    1、增加测试代码,JUnit出现红条

    2、修改产品代码

    3、JUnit出现绿条,任务完成

    (由于提前阅读了老师的学习指导,直接选择了绿条正确做法。)
    做法如截图






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

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

    (1)封装实际上使用方法(method)将类的数据隐藏起来,控制用户对类的修改和访问数据的程度,从而带来模块化(Modularity)和信息隐藏(Information hiding)的好处;接口(interface)是封装的准确描述手段。
    Dog类通过使用类和访问控制(private,public)隐藏了属性color,开放了接口setColor(),getColor(),bark()和toString。Dog类是一个模块,我们可以通过下面的代码使用它,测试代码与运行结果如下

    (2)我们可以用UML中的类图来描述类Dog:

    在UML 里,一个类的属性能显示它的名字,类型,初始化值,属性也可以显示private,public,protected。 类的方法能显示它们的方法名,参数,返回类型,以及方法的private,public,protected属性。其中:

    • +表示public
    • 表示 protected

    • -表示 private

    使用UML可以让我们不必关注细节。

    (3)Dog类和Cat类都有Color属性和相应的set和get方法,明显违反了前面提到的DRY原则,我们可以通过继承解决这个问题,把Color属性和相应方法放到父类Animal中,如以下UML较图所示:

    (注意UML类图中继承的表示法,是用一个带三角的直线指向父类)

    熟悉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,依赖倒置原则)

    练习

    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)时间

    步骤 耗时 百分比
    需求分析 25min 11.9%
    设计 30min 14.3%
    代码实现 90min 42.9%
    测试 45min 21.4%
    分析总结 20min 9.5%

    3.总结单元测试的好处

    (1)在产品代码中,各个类之间相互独立,互不影响,保证代码的独立性并且方便进行再次添加或减少。
    (2)代码更加清晰明确,模块化更加清晰。
    (3)代码出现问题时,更加容易进行维护和修改。
    (4)将产品代码和测试代码分开,更加方便使用者理解。

    实验体会

    通过本次试验,编写代码时,并不只是将源代码编译出来就万事大吉了,想编写一个较出色的程序时,还需要写出三种代码:伪代码、产品代码、测试代码。在作品完成初期,肯定会担心自己的程序会有Bug。
    要通过不断调试发现问题,才能使自己编写的代码更加实际意义,方便使用。通过测试,才能对自己的代码负责任。

  • 相关阅读:
    maven 设置日志级别
    浏览器工作原理:浅析浏览器中的页面
    浏览器工作原理:浅析浏览器中的页面
    解决uniapp的websocket连接在web和安卓正常,iOS连接不上的问题
    浏览器工作原理:浅析页面循环系统
    浏览器工作原理:浅析页面循环系统
    浏览器工作原理:浅析页面循环系统
    浅析如何使用WebSocket、SockJS、STOMP实现消息实时通讯功能:websocket/SocketJS/Stomp是什么及三者的关系、stomp协议格式、如何开启stomp、如何处理客服端发送的stomp、如何发消息给客服端、如何在任何地方发消息、如何给目标或指定用户发消息
    解决sockjs、stomp在uni-app端使用的坑
    浏览器工作原理:浅析页面循环系统
  • 原文地址:https://www.cnblogs.com/20145201lzx/p/5389382.html
Copyright © 2011-2022 走看看