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


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

    1实验内容

    • 初步掌握单元测试和TDD
    • 理解并掌握面向对象三要素:封装、继承、多态
    • 初步掌握UML建模
    • 熟悉S.O.L.I.D原则
    • 了解设计模式

    2. 初步掌握单元测试

    三种代码
    • 伪代码
    百分制转五分制:
       如果成绩小于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 "错误";
       }
    }
    
    • 测试代码(包含边界测试)
    //20155329!!!!
    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 if(MyUtil.percentage2fivegrade(-10) != "错误") {
                System.out.println("test failed 1!");
            }
            else if(MyUtil.percentage2fivegrade(115) != "错误")
                System.out.println("test failed 2!");
            //测试边界情况
            else 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!");
    
        }
    }
    
    
    • 测试结果:

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

    • TDD的一般步骤如下:
    明确当前要完成的功能,记录成一个测试列表
    快速完成编写针对此功能的测试用例
    测试代码编译不通过(没产品代码呢)
    编写产品代码
    测试通过
    对代码进行重构,并保证测试通过(重构下次实验练习)
    循环完成所有功能的开发
    IDEA TDD 使用:参考Intellj IDEA 简易教程-单元测试;积极主动敲代码,使用JUnit学习Jav
    
    

    -构建测试类
    -编写测试代码

     @Test
        public void testcharAt() throws Exception{
            assertEquals('S',a.charAt(0));
            assertEquals('g',a.charAt(5));
            assertEquals('r',a.charAt(11));
        }
    
    • 对 StringBufferDemo进行了测试
    public class StringBufferDemoTest extends TestCase {
        StringBuffer a = new StringBuffer("StringBuffer");//测试12个字符(<=16)
        StringBuffer b = new StringBuffer("StringBufferStringBuffer");//测试24个字符(>16&&<=34)
        StringBuffer c = new StringBuffer("StringBufferStringBufferStringBuffer");//测试36个字符(>=34)
        @Test
        public void testcharAt() throws Exception{
            assertEquals('S',a.charAt(0));
            assertEquals('g',a.charAt(5));
            assertEquals('r',a.charAt(11));
        }
        @Test
        public void testcapacity() throws Exception{
            assertEquals(28,a.capacity());
            assertEquals(40,b.capacity());
            assertEquals(52,c.capacity());
        }
        @Test
        public void testlength() throws Exception{
            assertEquals(12,a.length());
            assertEquals(24,b.length());
            assertEquals(36,c.length());
        }
        @Test
        public void testindexOf() throws Exception{
            assertEquals(0,a.indexOf("Str"));
            assertEquals(5,a.indexOf("gBu"));
            assertEquals(10,a.indexOf("er"));
        }
    }
    
    • 测试结果:

    -很幸运我们得到 输出 test passed!,代表通过测试。若我们不幸的失败了,那我们应该一个一个的测试用例都打印出来,去寻找是哪里出现了失败。

    以TDD的方式学习StringBuffer

    • 此任务主要锻炼我们自己写JUnit测试用例的能力。老师在教程里给出的代码如下:
    1   public class StringBufferDemo{        
    2   public static void main(String [] args){    
    3       StringBuffer buffer = new StringBuffer();    
    4       buffer.append('S');     
    5       buffer.append("tringBuffer");     
    6       System.out.println(buffer.charAt(1));     
    7       System.out.println(buffer.capacity();     
    8       System.out.println(buffer.indexOf("tring"));    
    9       System.out.println("buffer = " + buffer.toString());    
    10  }    
    11}    
    
    • 上面老师给出的代码中有四个方法需要测试,charAt()、capacity()、length()、indexOf

    -charAt():charAt(int i)的解释为:“返回此序列中指定索引处的 char 值。第一个 char 值在索引 0 处,第二个在索引 1 处,依此类推,这类似于数组索引。
    - indexOf(String s)则返回输入的子字符串的第一个字母在母字符串的位置
    - capacity()和length()的关系,前者是最大容量,length返回当前长度。
    
    

    -测试代码如下

    public class StringBufferDemoTest extends TestCase {
        StringBuffer a = new StringBuffer("StringBuffer");//测试12个字符(<=16)
        StringBuffer b = new StringBuffer("StringBufferStringBuffer");//测试24个字符(>16&&<=34)
        StringBuffer c = new StringBuffer("StringBufferStringBufferStringBuffer");//测试36个字符(>=34)
        @Test
        public void testcharAt() throws Exception{
            assertEquals('S',a.charAt(0));
            assertEquals('g',a.charAt(5));
            assertEquals('r',a.charAt(11));
        }
        @Test
        public void testcapacity() throws Exception{
            assertEquals(28,a.capacity());
            assertEquals(40,b.capacity());
            assertEquals(52,c.capacity());
        }
        @Test
        public void testlength() throws Exception{
            assertEquals(12,a.length());
            assertEquals(24,b.length());
            assertEquals(36,c.length());
        }
        @Test
        public void testindexOf() throws Exception{
            assertEquals(0,a.indexOf("Str"));
            assertEquals(5,a.indexOf("gBu"));
            assertEquals(10,a.indexOf("er"));
        }
    }
    
    

    -此次代码分别对长度不同的三个字符串进行测试

    • 测试结果

    二、面向对象三要素:封装、继承、多态

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

    使用StarUML对实验二中的代码进行建模

    • 下载安装StarUML
    • 添加project
    • 进行建模后如下图

    三、设计模式

    • 面向对象三要素是“封装、继承、多态”,任何面向对象编程语言都会在语法上支持这三要素。如何借助抽象思维用好三要素特别是多态还是非常困难的,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,依赖倒置原则)

    对MyDoc类进行扩充,让其支持Double类,初步理解设计模式
    • OCP是OOD中最重要的一个原则,要求软件实体(类,模块,函数等)应该对扩充开放,对修改封闭。也就是说,软件模块的行为必须是可以扩充的,在应用需求改变或需要满足新的应用需求时,我们要让模块以不同的方式工作;同时,模块的源代码是不可改动的,任何人都不许修改已有模块的源代码。OCP可以用以下手段实现:(1)抽象和继承,(2)面向接口编程。
    //20155329!!
            import java.lang.*;
    public class Complex {
        //定义属性并生成getter,setter
        double RealPart;
        double ImagePart;
        public double getRealPart() {
            return RealPart;
        }
        public void setRealPart(double realPart) {
            this.RealPart=realPart;
        }
        public double getImagePart() {
            return ImagePart;
        }
        public void setImagePart(double imagePart) {
            this.ImagePart=imagePart;
        }
        //定义构造函数
        public Complex(double R, double I) {
            RealPart = R;
            ImagePart = I;
        }/
        //Override Object
        public boolean equals(Complex obj1) {
            if (this.getRealPart () == obj1.getRealPart () && this.getImagePart () == obj1.getImagePart ())
                return true;
            else return false;
        }
        //定义公有方法:加减乘除
        public String toString() {
            return "第一个"+RealPart + " 第二个" + ImagePart ;
        }
        public Complex ComplexAdd(Complex obj) {
            return new Complex ( RealPart + obj.getRealPart (), ImagePart + obj.getImagePart () );
        }
        public Complex ComplexSub(Complex obj) {
            return new Complex ( RealPart - obj.getRealPart (), ImagePart - obj.getImagePart () );
        }
        public Complex ComplexMulti(Complex obj) {
            return new Complex ( RealPart * obj.getRealPart () - ImagePart * obj.getImagePart (), RealPart * obj.getImagePart () + ImagePart * obj.getRealPart () );
        }
        public Complex ComplexDiv(Complex obj){
            return new Complex ( RealPart / obj.getRealPart () - ImagePart / obj.getImagePart (), RealPart / obj.getImagePart () + ImagePart / obj.getRealPart () );
        }
    }
    
    

    以TDD的方式开发一个复数类Complex

    TDD的编码节奏是:

    1. 增加测试代码,JUnit出现红条
    2. 修改产品代码
    3. Unit出现绿条,任务完成
      -伪代码:
    (1)属性:复数包含实部和虚部两个部分,
    double RealPart;复数的实部
    double ImagePart;复数的虚部
    getRealPart():返回复数的实部
    getImagePart();返回复数的虚部
    setRealPart():设置复数的实部
    setImagePart();设置复数的虚部
    输出形式:a+bi
    (2)方法:
    ①定义构造函数
    public Complex()
    public Complex(double R,double I)
    ②定义公有方法:加减乘除
    Complex ComplexAdd(Complex a):实现复数加法
    Complex ComplexSub(Complex a):实现复数减法
    Complex ComplexMulti(Complex a):实现复数乘法
    Complex ComplexDiv(Complex a):实现复数除法
    ③Override Object
    public String toString():将计算结果转化为字符串形式并输出
    
    • 测试代码
    public class ComplexTest extends TestCase {
        Complex c1 = new Complex(0, 3);
        Complex c2 = new Complex(-1, -1);
        Complex c3 = new Complex(2,1);
        @Test
        public void testgetRealPart() throws Exception {
            assertEquals(-1.0, Complex.getRealPart(-1.0));
            assertEquals(5.0, Complex.getRealPart(5.0));
            assertEquals(0.0, Complex.getRealPart(0.0));
        }
        @Test
        public void testgetImagePart() throws Exception {
            assertEquals(-1.0, Complex.getImagePart(-1.0));
            assertEquals(5.0, Complex.getImagePart(5.0));
            assertEquals(0.0, Complex.getImagePart(0.0));
        }
        @Test
        public void testComplexAdd() throws Exception {
            assertEquals("-1.0+2.0i", c1.ComplexAdd(c2).toString());
            assertEquals("2.0+4.0i", c1.ComplexAdd(c3).toString());
            assertEquals("1.0", c2.ComplexAdd(c3).toString());
        }
        @Test
        public void testComplexSub() throws Exception {
            assertEquals("1.0+4.0i", c1.ComplexSub(c2).toString());
            assertEquals("-2.0+2.0i", c1.ComplexSub(c3).toString());
            assertEquals("-3.0 -2.0i", c2.ComplexSub(c3).toString());
        }
        @Test
        public void testComplexMulti() throws Exception {
            assertEquals("3.0 -3.0i", c1.ComplexMulti(c2).toString());
            assertEquals("-3.0+6.0i", c1.ComplexMulti(c3).toString());
            assertEquals("-1.0 -3.0i", c2.ComplexMulti(c3).toString());
        }
        @Test
        public void testComplexComplexDiv() throws Exception {
            assertEquals("-1.5 -1.5i", c1.ComplexDiv(c2).toString());
            assertEquals("1.2+0.6i", c1.ComplexDiv(c3).toString());
            assertEquals("-0.6 -0.6i", c2.ComplexDiv(c3).toString());
        }
    }
    
    • 产品代码
    public class Complex{
        private double r;
        private double i;
    
        public Complex(double r, double i) {
            this.r = r;
            this.i = i;
        }
    
        public static double getRealPart(double r) {
            return r;
        }
    
        public static double getImagePart(double i) {
            return i;
        }
    
        public Complex ComplexAdd(Complex c) {
            return new Complex(r + c.r, i + c.i);
        }
        public Complex ComplexSub(Complex c) {
            return new Complex(r - c.r, i - c.i);
        }
        public Complex ComplexMulti(Complex c) {
            return new Complex(r * c.r - i * c.i, r * c.i + i * c.r);
        }
        public Complex ComplexDiv(Complex c) {
            return new Complex((r * c.i + i * c.r)/(c.i * c.i + c.r * c.r), (i * c.i + r * c.r)/(c.i * c.i + c.r * c.r));
        }
    
        public String toString() {
            String s = " ";
            if (i > 0)
                s =  r + "+" + i + "i";
            if (i == 0)
                s =  r + "";
            if (i < 0)
                s = r + " " + i + "i";
            return s;
        }
    }
    

    PSP(Personal Software Process)时间

    步骤 耗时 百分比
    需求分析 10min 6.6%
    设计 10min 6.6%
    代码实现 60min 40%
    测试 50min 33.3%
    分析总结 20min 13.3%

    实验体会和总结

    再一次修改自己的实验报告,感觉到自己的很多不足,首先做实验只求结果,不问为什么对我的实验报告看起来很枯燥。重温本次实验,感觉到了课堂实践《在IDEA中以TDD的方式对String类和Arrays类进行学习》不会做,完全是咎由自取,只需要当初做实验的时候多问几个为什么就好了。

    写伪代码,测试代码,产品代码。在以前我会认为写个代码有思路就可以直接下手了。通过这次重温实验,深刻感受到了TDD的好处,伪代码就是一个详细版的思路,翻译伪代码后,进行代码测试,边缘测试,消除bug。最后才能算得上是一个优秀的代码。这也是为什么自己总感觉自己的代码是正确的而总是被扣很多分

    在接下来的计算机实习中,虽然我不是选的java。但是我会将这一次实验所得用入我的C语言实习中,争取做出让自己满意的产品代码

  • 相关阅读:
    231. Power of Two
    204. Count Primes
    205. Isomorphic Strings
    203. Remove Linked List Elements
    179. Largest Number
    922. Sort Array By Parity II
    350. Intersection of Two Arrays II
    242. Valid Anagram
    164. Maximum Gap
    147. Insertion Sort List
  • 原文地址:https://www.cnblogs.com/hpl20155329/p/6751756.html
Copyright © 2020-2023  润新知