實驗二 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步驟:僞代碼(思路)→ 測試代碼(產品預期功能)→ 產品代碼(實現預期功能),這種開發方法叫「測試驅動開發」html

  • 僞代碼:僞代碼與具體編程語言無關,不要寫與具體編程語言語法相關的語句(如用malloc分配內存,這樣只能用C語言編程了),僞代碼從意圖層面來解決問題,最終,僞代碼是產品代碼最天然的、最好的註釋。java

  • 故根據實驗題目要求,咱們應先寫出相應的「僞代碼」以便於咱們完成編程,僞代碼以下:
百分制轉五分制:
   若是成績小於60,轉成「不及格」
   若是成績在60與70之間,轉成「及格」
   若是成績在70與80之間,轉成「中等」
   若是成績在80與90之間,轉成「良好」
   若是成績在90與100之間,轉成「優秀」
   其餘,轉成「錯誤」
  • 可見使用語言簡潔明瞭,隨後將僞代碼轉爲產品代碼便可。git

  • 產品代碼:用以實現特定功能的程序或機器語言。
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

  • 也成功了app

  • 再看看異常狀況下的測試:編程語言

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

  • 成功了。ide

  • 值得一提的是,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傳代碼哦)

相關文章
相關標籤/搜索