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

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


    实验报告封面:

    课程:Java程序设计  班级:1652班  姓名:王高源 学号:20165225
    
    指导教师:娄嘉鹏 实验日期:2018年4月16日
    
    实验时间:3:35 - 5:15 实验序号:实验二
    
    实验名称:Java面向对象程序设计
    
    实验内容:
    1.初步掌握单元测试和TDD
    2.理解并掌握面向对象三要素:封装、继承、多态
    3.初步掌握UML建模
    4.熟悉S.O.L.I.D原则
    5.了解设计模式
    
    实验要求:
    
    实现百分制成绩转成“优、良、中、及格、不及格”五级制成绩的功能
    
    

    实验内容及步骤:

    注:以下许多代码都是老师给好的,仅稍作修改。
    单元测试
    • TDD步骤:伪代码(思路)→ 测试代码(产品预期功能)→ 产品代码(实现预期功能),这种开发方法叫“测试驱动开发”

    • 伪代码:伪代码与具体编程语言无关,不要写与具体编程语言语法相关的语句(如用malloc分配内存,这样只能用C语言编程了),伪代码从意图层面来解决问题,最终,伪代码是产品代码最自然的、最好的注释。

    • 故根据实验题目要求,我们应先写出相应的“伪代码”以便于我们完成编程,伪代码如下:

    百分制转五分制:
       如果成绩小于60,转成“不及格”
       如果成绩在60与70之间,转成“及格”
       如果成绩在70与80之间,转成“中等”
       如果成绩在80与90之间,转成“良好”
       如果成绩在90与100之间,转成“优秀”
       其他,转成“错误”
    
    • 可见使用语言简洁明了,随后将伪代码转为产品代码即可。

    • 产品代码:用以实现特定功能的程序或机器语言。

    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 "错误";
        }
    }
    
    • 写了产品代码后,我们还要写测试代码,证明自己的代码没有问题,这样才能将代码放心交到用户手中。

    • 测试代码:用以对产品代码进行测试的代码。

    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!");
        }
    }
    
    • 运行结果如下:

    image

    • 成功了。

    • 不过只测一组就是有偷懒嫌疑了,现在我们把一般情况都试一下:

    image

    • 也成功了

    • 再看看异常情况下的测试:

    image

    • 这时我们发现了程序bug:判断不及格时没有要求成绩大于零,于是我们修改源代码,增加对负分的判断:
    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 "错误";
       }
    }
    
    • 这时候再重新测一下异常,发现通过了:

    image

    • 可喜可贺。
    • 但是我们还没有测试边界情况,于是我们再对输入为“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!"); 
        }
    }
    
    • 结果如预期般出错了:

    image

    • 于是我们再把源代码改成了"<=":
    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 "错误";
       }
    }
    
    • 再测试一下:

    image

    • 成功了。

    • 值得一提的是,Java中有单元测试工具JUnit来辅助进行TDD。

    错误来的太突然:
    • 按照老师给的步骤来走不小心就出现下图,以为是网络问题,结果换了网也没有用:

    image

    • 然后试着什么也不输入直接点Browse repositories...,然后成功了。
    • 接下来点击绿色的那个安装,又出错了:

    image

    • 气死了,再下一次,发现他又好了...

    • 回到原题。

    • 从网上下了一个everything用于查找junit.jar。

    • 然后用老师给的新方法去测试了一下之前的代码:

    image

    • 成功了,然后可能是版本问题,我的小绿条变成了小绿勾。

    • 其实之前按照攻略来是失败了的,不过还好有好看的助教学姐指点了我一下,才顺利完成测试。

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

    • 抽象:即“求同存异、去粗取精”的过程。将若干事物中相同的部分进行剥离整理,并形成具有某特定功能的产品,这一过程即为抽象。过程抽象的结果是函数,数据抽象的结果是抽象数据类型其显而易见的好处是(在程序设计中)减少了代码大重复性,提高了效率。

    • 封装:将与某一将数据与相关行为包装在一起以实现信息就隐藏,核心内容是模块化和信息隐藏,与此相伴的是接口的使用。

    • 封装:

    public class Dog {
    private String color;
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    public String bark(){
        return "汪汪";
    }
    public String toString(){
        return "The Dog's color is " + this.getColor() +", and it shouts "+ this.bark() + "!";
    }
    }
    
    • 检测:
    public class DogTest {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.setColor("Yellow");
        getInfo(d);
    }
    public static void getInfo(Dog d) {
        System.out.println(d.toString());
    }
    }
    
    • 下图是我用starUML弄出来的建模(自学软件真的很累哦):

    image

    以TDD的方式研究学习StringBuffer
    • 关于StringBuffer的代码如下:
    public class StringBufferDemo {
      public static void main(String [] args) {
        StringBuffer buffer = new StringBuffer();
        buffer.append('S');
        buffer.append("tringBuffer");
        System.out.println(buffer.charAt(i));
        System.out.println(buffer.capacity());
        System.out.println(buffer.length());
        System.out.println(buffer.indexOf("tring"));
        System.out.println("buffer = " + buffer.toString());
      }
    } 
    
    • 然而老师说这个代码不可以直接用,在我把第七行的括号加上后,便完美运行了。

    • 在老师给出的使用JUnit学习Java中,有四个需要我们去测试的东西:charAt()、capacity()、length()和indexOf。

    • 基于以上,我们的测试代码可为:

    import junit.framework.TestCase;
    import org.junit.Test;
    public class StringBufferDemoTest extends TestCase {
        StringBuffer a = new StringBuffer("StringBuffer");
        StringBuffer b = new StringBuffer("StringBufferStringBuffer");
        StringBuffer c = new StringBuffer("StringBufferStringBufferStringBuffer");
        @Test
        public void testcharAt() {
            assertEquals('S',a.charAt(0));
            assertEquals('e',b.charAt(10));
            assertEquals('f',c.charAt(20));;
        }
        @Test
        public void testcapacity() {
            assertEquals(28,a.capacity());
            assertEquals(40,b.capacity());
            assertEquals(52,c.capacity());
        }
        @Test
        public void testindexOf() {
            assertEquals(0,a.indexOf("Str"));
            assertEquals(3,b.indexOf("ing"));
            assertEquals(10,c.indexOf("er"));
        }
        @Test
        public void testlength() {
            assertEquals(12,a.length());
            assertEquals(24,b.length());
            assertEquals(48,c.length());
        }
    }
    
    • 理所当然的我们测试一下:

    image

    • 成功了。
    S.O.L.I.D原则
    • SRP(Single Responsibility Principle,单一职责原则)
      对象提供单一职责的高度封装,对象的改变仅仅依赖于单一职责的改变

    • OCP(Open-Closed Principle,开放-封闭原则)
      即对扩充开放(功能可增加),对修改封闭(源代码不可改动)

    • OCP实现手段:(1)抽象和继承,(2)面向接口编程
      LSP(Liskov Substitusion Principle,Liskov替换原则)
      子类必须可以被其基类所代,父类型对象可以被子类型对象所取代
      ISP(Interface Segregation Principle,接口分离原则)
      客户不应该依赖他们并未使用的接口

    • DIP(Dependency Inversion Principle,依赖倒置原则)

    • 示例如下(自己学号%6取余):

    abstract class Data {
        abstract public void DisplayValue();
    }
    class Integer extends  Data {
        int value;
        Integer() {
            value=100;
        }
        public void DisplayValue(){
            System.out.println (value);
        }
    }
    class Short extends Data {
        short value;
        Short() {
            value = 5225;
        }
        public void DisplayValue(){
            System.out.println (value);
        }
    }
    abstract class Factory {
        abstract public Data CreateDataObject();
    }
    class IntFactory extends Factory {
        public Data CreateDataObject(){
            return new Integer();
        }
    }
    class ShortFactory extends Factory {
        public Data CreateDataObject(){
            return new Short();
        }
    }
    class Document {
        Data pd;
        Document(Factory pf){
            pd = pf.CreateDataObject();
        }
        public void DisplayData(){
            pd.DisplayValue();
        }
    }
    public class MyDoc {
        static Document d;
        public static void main(String[] args) {
            d = new Document(new ShortFactory());
            d.DisplayData();
        }
    }
    
    • 这是一个支持short类的代码,关于学号取余,若想改成其他,只需要改一下这里:
    class ??? extends Data {
        short value;
        Short() {
            value = 5225;
        }
        public void DisplayValue(){
            System.out.println (value);
        }
    }
    
    class ???Factory extends Factory {
        public Data CreateDataObject(){
            return new ???();
        }
    }
    
    public class MyDoc {
        static Document d;
        public static void main(String[] args) {
            d = new Document(new ???Factory());
            d.DisplayData();
        }
    }
    
    
    • 这样一来代码便符合了OCP原则,使代码有良好的可扩充性、可维护性。
    练习:使用TDD的方式设计关实现复数类Complex
    • 伪代码:
    Complex类要输出实部,输出虚部,并按照a+bi的形式输出复数。
    Complex类中有两个变量,实部RealPart和虚部ImaginePart;,
    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 boolean equals(Object obj)
    public String toString():将复数输出成a+bi的格式。
    
    
    • 将其转换成产品代码:
    import java.util.Scanner;
    public class MyComplex {
        static int r;
        static int i;
        private double m;
        private double n;
        public static int getRealPart(int RealPart){
            r = RealPart;
            return r;
        }
        public static int getImaginePart(int ImaginePart){
            i = ImaginePart;
            return i;
        }
        public MyComplex(double m, double n) {
            this.m = m;
            this.n = n;
        }
        public MyComplex add(MyComplex c) {
            return new MyComplex(m + c.m, n + c.n);
        }
        public MyComplex minus(MyComplex c) {
            return new MyComplex(m - c.m, n - c.n);
        }
        public MyComplex multiply(MyComplex c) {
            return new MyComplex(m * c.m - n * c.n, m * c.n + n * c.m);
        }
        public String toString() {
            String s = "";
            if (n > 0)
                s = "(" + m + "+" + n + "i" + ")";
            if (n == 0)
                s = "(" + m + ")";
            if (n < 0)
                s = "(" + m + n + "i" + ")";
            return s;
        }
    }
    
    
    • 测试代码可为:
    import org.junit.Test;
    import static org.junit.Assert.*;
    public class MyComplexTest {
        MyComplex a=new MyComplex(1,2);
        MyComplex b=new MyComplex(1,-4);
        MyComplex c=new MyComplex(19,0);
        MyComplex d=new MyComplex(0,-3);
        MyComplex e=new MyComplex(0,0);
        @Test
        public void getRealPart() throws Exception {
            assertEquals(1, MyComplex.getRealPart(1));
            assertEquals(-1, MyComplex.getRealPart(-1));
            assertEquals(5, MyComplex.getRealPart(5));
            assertEquals(22, MyComplex.getRealPart(22));
            assertEquals(-100, MyComplex.getRealPart(-100));
            assertEquals(0, MyComplex.getRealPart(0));
        }
        @Test
        public void getImaginePart() throws Exception {
            assertEquals(1, MyComplex.getImaginePart(1));
            assertEquals(-1, MyComplex.getImaginePart(-1));
            assertEquals(5, MyComplex.getImaginePart(5));
            assertEquals(22, MyComplex.getImaginePart(22));
            assertEquals(-100, MyComplex.getImaginePart(-100));
            assertEquals(0, MyComplex.getImaginePart(0));
        }
        @Test
        public void add() throws Exception {
            assertEquals("(2.0-2.0i)", a.add(b).toString());
            assertEquals("(20.0+2.0i)", a.add(c).toString());
            assertEquals("(1.0-1.0i)", a.add(d).toString());
            assertEquals("(1.0+2.0i)", a.add(e).toString());
        }
        @Test
        public void minus() throws Exception {
            assertEquals("(0.0+6.0i)", a.minus(b).toString());
            assertEquals("(-18.0+2.0i)", a.minus(c).toString());
            assertEquals("(1.0+5.0i)", a.minus(d).toString());
            assertEquals("(1.0+2.0i)", a.minus(e).toString());
        }
        @Test
        public void multiply() throws Exception {
            assertEquals("(9.0-2.0i)", a.multiply(b).toString());
            assertEquals("(19.0+38.0i)", a.multiply(c).toString());
            assertEquals("(6.0-3.0i)", a.multiply(d).toString());
            assertEquals("(0.0)", a.multiply(e).toString());
        }
    }
    
    
    • 测试成功:

    image

    实验体会与总结
    • 说实话,这次实验要我编程我是不会编的..但是还好老师给了模板,只需要改一下就好了。

    • 在实验有了代码支撑后,比较累的地方就是要看好多好多长博客,还有以上提到的一些软件的操作方法你都要学(虽然老师有给出UML的另一个建模方法,但是我还是用了别的)。

    • 值得一提的是,这次学到的东西能让我更轻松的去修正代码bug,减少了之后修复所需要的大量精力。

    • 但是不管怎么说,过程还是很累的,有时候都想把博客全部关掉,好好睡一下,好在最后我写完了。

    • 还是要继续加油呀!

    • 码云链接(这也是我第一次规范书写git传代码哦)

  • 相关阅读:
    有一种尺度叫圆融
    十大经典排序算法
    Maximal Square
    Word Break
    Flatten List
    Triangle
    Paint Fence
    Longest Increasing Continuous Subsequence
    Minimum Size Subarray Sum
    Letter Combinations of a Phone Number
  • 原文地址:https://www.cnblogs.com/nmsl123/p/8847718.html
Copyright © 2011-2022 走看看