zoukankan      html  css  js  c++  java
  • 20145211 《Java程序设计》实验报告二:Java面向对象程序设计

    实验要求

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

    实验内容

    • 单元测试
    • 面向对象三要素
    • 设计模式初步
    • 练习

    实验步骤(实现四则运算,并进行测试)

    单元测试

    1. 伪代码:以简洁的自然语言表明设计步骤;
    百分制转五分制:
       如果成绩小于60,转成“不及格”
       如果成绩在60与70之间,转成“及格”
       如果成绩在70与80之间,转成“中等”
       如果成绩在80与90之间,转成“良好”
       如果成绩在90与100之间,转成“优秀”
       其他,转成“错误”
    
    1. 产品代码:用以实现特定功能的程序或机器语言;
    package exp1;
    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. 测试代码:用以对产品代码进行测试的代码;
    package lab02;
    
    import org.junit.Test;
    
    import static org.junit.Assert.*;
    public class MyUtilTest {
    
        @Test
        public void testPercentage2fivegrade() throws Exception {
            assertEquals("不及格",MyUtil.percentage2fivegrade(56));
            assertEquals("及格",MyUtil.percentage2fivegrade(66));
            assertEquals("中等",MyUtil.percentage2fivegrade(76));
            assertEquals("良好",MyUtil.percentage2fivegrade(86));
            assertEquals("优秀",MyUtil.percentage2fivegrade(96));
        }
    }
    

    运行结果如下:

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

    • TDD:先写测试代码,然后再写产品代码的开发方法。
    • TDD的一般步骤如下:
    1. 明确当前要完成的功能,记录成一个测试列表
    2. 快速完成编写针对此功能的测试用例
    3. 测试代码编译不通过(没产品代码呢)
    4. 编写产品代码
    5. 测试通过
    6. 对代码进行重构,并保证测试通过(重构下次实验练习)
    7. 循环完成所有功能的开发
    • TDD的编码流程:
      1. 增加测试代码,JUnit出现红色段码
      2. 修改产品代码
      3. 实现
    • IDEA环境:鼠标右键->Go To ->Test

    面向对象三要素

    • 抽象
      即“取其精华去其糟粕”的过程。将若干事物中相同的部分进行剥离整理,并形成具有某特定功能的产品,这一过程即为抽象。
      过程抽象的结果是函数,数据抽象的结果是抽象数据类型其显而易见的好处是(在程序设计中)减少了代码大重复性,提高了效率。
    • 封装、继承与多态
    1. 面向对象(Object-Oriented)的三要素包括:封装、继承、多态。面向对象的思想涉及到软件开发的各个方面,如面向对象分析(OOA)、面向对象设计(OOD)、面向对象编程实现(OOP)。OOA根据抽象关键的问题域来分解系统,关注是什么(what)。OOD是一种提供符号设计系统的面向对象的实现过程,用非常接近问题域术语的方法把系统构造成“现实世界”的对象,关注怎么做(how),通过模型来实现功能规范。OOP则在设计的基础上用编程语言(如Java)编码。贯穿OOA、OOD和OOP的主线正是抽象。
    2. 封装:将数据与相关行为包装在一起以实现信息就隐藏。封装实际上使用方法(method)将类的数据隐藏起来,控制用户对类的修改和访问数据的程度,从而带来模块化(Modularity)和信息隐藏(Information hiding)的好处;接口(interface)是封装的准确描述手段。 Dog类通过使用类和访问控制(private,public)隐藏了属性color,开放了接口setColor(),getColor(),bark()和toString。
    3. 继承:以封装为基础,一个类的定义可以基于另外一个已经存在的类,即子类基于父类,从而实现父类代码的重用。其更为广泛而重要的作用是实现多态。
    • 例子:

    封装

    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());
    }
    }
    

    设计模式

    • S.O.L.I.D原则
    1. SRP(Single Responsibility Principle,单一职责原则)
      对象提供单一职责的高度封装,对象的改变仅仅依赖于单一职责的改变
    2. OCP(Open-Closed Principle,开放-封闭原则)
      即对扩充开放(功能可增加),对修改封闭(源代码不可改动)
      OCP实现手段:(1)抽象和继承,(2)面向接口编程
    3. LSP(Liskov Substitusion Principle,Liskov替换原则)
      子类必须可以被其基类所代,父类型对象可以被子类型对象所取代
    4. ISP(Interface Segregation Principle,接口分离原则)
      客户不应该依赖他们并未使用的接口
    5. DIP(Dependency Inversion Principle,依赖倒置原则)
    • 模式与设计模式
      模式是某外在环境(Context) 下﹐对特定问题(Problem)的惯用解决之道。其中最重要的是设计模式。
    • 设计模式实示例
      设计模式四个基本元素
      Pattern name:描述模式,便于交流,存档
      Problem:描述何处应用该模式
      Solution:描述一个设计的组成元素,不针对特例
      Consequence:应用该模式的结果和权衡

    练习

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

    伪代码

    1)复数类ComplexNumber的属性
      realPart: 实部,代表复数的实数部分
      imaginPart: 虚部,代表复数的虚数部分
    2)复数类ComplexNumber的方法
      ComplexNumber() 构造函数,将实部,虚部都置为0
      ComplexNumber(double realPart, double imaginPart) 构造函数,创建复数对象的同时完成复数的实部,虚部的初始化
      getRealPart() 获取实部
      getImaginaryPart() 获取虚部
      getRealPart(double realPart) 设置实部
      getImaginaryPart(double imaginPart) 设置虚部
      ComplexAdd(ComplexNumber c)    复数相加
      ComplexAdd(double realPart2)   复数相加
      ComplexMinus(ComplexNumber c)  复数相减
      ComplexMinus(double realPart2) 复数相减
      ComplexMulti(ComplexNumber c)  复数相乘
      ComplexMulti(double realPart2) 复数相乘
      toString() 把当前复数对象的实部,虚部组合成a+bi的字符串形式
    
    • 测试代码
    package lab02;
    
    import static junit.framework.Assert.*;
    import junit.framework.TestCase;
    import org.junit.Test;
    
    
    public class ComplexNumberTest extends TestCase {
        ComplexNumber c1 = new ComplexNumber(3,5);
        ComplexNumber c2 = new ComplexNumber(3,5);
        double a = 5;
        @Test
        public void testAdd1() throws Exception {
            c1.ComplexAdd(c2);
            assertEquals(6.0, c1.getRealPart());
            assertEquals(10.0, c1.getImaginPart());
        }
        @Test
        public void testAdd2() throws Exception {
            c1.ComplexAdd(a);
            assertEquals(8.0, c1.getRealPart());
            assertEquals(5.0, c1.getImaginPart());
        }
        @Test
        public void testMinus1() throws Exception {
            c1.ComplexMinus(c2);
            assertEquals(0.0, c1.getRealPart());
            assertEquals(0.0, c1.getImaginPart());
        }
        public void testMinus2() throws Exception {
            c1.ComplexMinus(a);
            assertEquals(-2.0, c1.getRealPart());
            assertEquals(5.0, c1.getImaginPart());
        }
        @Test
        public void testMulti1() throws Exception {
            c1.ComplexMulti(c2);
            assertEquals(9.0, c1.getRealPart());
            assertEquals(25.0, c1.getImaginPart());
        }
        public void testMulti2() throws Exception {
            c1.ComplexMulti(a);
            assertEquals(15.0, c1.getRealPart());
            assertEquals(5.0, c1.getImaginPart());
        }
    }
    
    • 产品代码
    package lab02;
    
    public class ComplexNumber {
        private double realPart;
        private double imaginPart;
        public ComplexNumber(){
            double realPart;
            double imaginPart;
        }
        public ComplexNumber(double r, double i){
            double realPart;
            double imaginPart;
            this.realPart = r;
            this.imaginPart = i;
        }
        public double getRealPart(){
            return realPart;
        }
        public double getImaginPart(){
            return imaginPart;
        }
        public void setRealPart(double d){
            this.realPart = d;
        }
        public void setImaginPart(double d){
            this.imaginPart = d;
        }
        public void ComplexAdd(ComplexNumber c){
            this.realPart += c.realPart;
            this.imaginPart += c.imaginPart;
        }
        public void ComplexAdd(double c){
            this.realPart += c;
        }
        public void ComplexMinus(ComplexNumber c){
            this.realPart -= c.realPart;
            this.imaginPart -= c.imaginPart;
        }
        public void ComplexMinus(double c){
            this.realPart -= c;
        }
        public void ComplexMulti(ComplexNumber c){
            this.realPart *= c.realPart;
            this.imaginPart *= c.imaginPart;
        }
        public void ComplexMulti(double c){
            this.realPart *= c;
        }
        @Override
        public String toString(){
            return String.format("%f + %fi", this.getRealPart(),this.getImaginPart());
        }
    }
    

    UML建模

    • 利用StarUML软件进行UML建模,可以将以上思路进行具象化表示
      显示如下,很清楚地展现了每个类的成员变量、方法函数:

    需求分析

    1. 在代码一的基础上,实现模块的划分;
    2. 对一些常见用例进行测试。

    分析总结与实验体会(感悟、思考等)

    • 其实还是觉得比较有意思,虽然很多东西最开始不会,但我感到很新鲜,有学习的动力!

    • 了Junit单元测试,从表面上看,每个单元程序都编写测试代码似乎是增加了工作量,但是其实这些代码不仅为你织起了一张保护网,而且还可以帮助你快速定位错误从而使你大大减少修复BUG的时间。

    • 再也不用每次通过printf来判断哪里出错了,感觉逼格瞬间提升了。

    • PSP(Personal Software Process)时间:

    步骤 耗时 百分比
    需求分析 10min 5%
    设计 10min 5%
    代码实现 60min 32%
    测试 75min 40%
    分析总结 30min 16%

    参考资料

  • 相关阅读:
    BZOJ 1449: [JSOI2009]球队收益 最小费用最大流 网络流
    HDU 4348 To the moon 主席树 在线更新
    省选模拟赛20180416
    线性基总结
    Write-up-Bulldog2
    [Write-up]BSides-Vancouver
    Write-up-Bob_v1.0.1
    Genymotion设置代理至BurpSuite和Charles
    PE之RVA转FOA
    django的序列化
  • 原文地址:https://www.cnblogs.com/nostalgia-/p/5402837.html
Copyright © 2011-2022 走看看