標籤:
註:由於網路卡頓,部分內容在自己電腦上的eclipse上完成
課程:Java程式設計 班級: 1351
姓名:薑文敏 學號:20135112
成績: 指導教師:婁嘉鵬 實驗日期:2015.05.06
實驗密級: 預習程度: 實驗時間:2015年5月8日-5月9日
儀器組次: 必修/選修:選修 實驗序號:2
實驗名稱:Java物件導向程式設計
實驗目的與要求:
1.沒有Linux基礎的同學建議先學習《Linux基礎入門(新版)》《Vim編輯器》 課程
2.完成實驗、撰寫實驗報告,實驗報告以部落格方式發表在部落格園,注意實驗報告重點是運行結果,遇到的問題(工具尋找,安裝,使用,程式的編輯,調試,運行等)、解決辦法(空洞的方法如“查網路”、“問同學”、“看書”等一律得0分)以及分析(從中可以得到什麼啟示,有什麼收穫,教訓等)。報告可以參考範飛龍老師的指導
3. 嚴禁抄襲,有該行為者實驗成績歸零,並附加其他懲罰措施。
4. 請大家先在實驗樓中的~/Code目錄中用自己的學號建立一個目錄,代碼和UML圖要放到這個目錄中,中沒有學號的會要求重做,然後跟著下面的步驟練習。
實驗儀器:
一、實驗內容:
1. 初步掌握單元測試和TDD
2. 理解並掌握物件導向三要素:封裝、繼承、多態
3. 初步掌握UML建模
4. 熟悉S.O.L.I.D原則
5. 瞭解設計模式
二、實驗過程:
(一)單元測試
1.以“百分制轉五分制”為例,介紹三種代碼
(1)虛擬碼 (2)產品代碼 (3)測試代碼
2.按照實驗說明裡的要求,將代碼輸入,並運行出測試結果:
(2)TDD(Test Driven Devlopment, 測試驅動開發)
TDD的一般步驟如下:
- 明確當前要完成的功能,記錄成一個測試清單
- 快速完成編寫針對此功能的測試案例
- 測試代碼編譯不通過(沒產品代碼呢)
- 編寫產品代碼
- 測試通過
- 對代碼進行重構,並保證測試通過(重構下次實驗練習)
- 迴圈完成所有功能的開發
關於測試載入器的使用:
開啟Eclipse,單擊File->New->Java Project建立一個TDDDemo的Java項目;
在TDDDemo項目中,把滑鼠放到項目名TDDDemo上,單擊右鍵,在彈出的菜單中選定New->Source Folder建立一個測試目錄test;
把滑鼠放到test目錄上,單擊右鍵,在彈出的菜單中選定New->JUnit Test Case建立一個測試案例類MyUtilTest;
由此,根據給出的實驗代碼輸入,得出實驗結果:
(二)物件導向三要素
(1)抽象 (2)封裝、繼承、多態
用UML中的類圖來描述類Dog,首先在實驗樓的環境中開啟shell,在命令列中輸入umbrello,開啟UML建模軟體umbrello;
先單擊工具列上的類表徵圖,再在class diagram(類圖)中單擊一下,會彈出一個框,輸入類名Dog;
把滑鼠放到Dog類上,單擊右鍵,選擇Properties,在彈出的對話方塊中的Display中去掉Public Only選項;
把滑鼠放到Dog類上,單擊右鍵,選擇New->Attribute,在彈出的對話方塊中的填好Type,Name,並選好Visibility;
把滑鼠放到Dog類上,單擊右鍵,選擇New->Operation,在彈出的對話方塊中的填好Type,Name,並選好Visibility。
在UML 裡,一個類的屬效能顯示它的名字,類型,初始化值,屬性也可以顯示private,public,protected。 類的方法能顯示它們的方法名,參數,傳回型別,以及方法的private,public,protected屬性。其中:
- +表示public
- #表示 protected
- -表示 private
操作結果如下:
將檔案儲存為“jiangwenmin”,存在Code/20135112下
相對應的java代碼為:
(三)設計模式初步
S.O.L.I.D原則
物件導向三要素是“封裝、繼承、多態”,任何物件導向程式設計語言都會在文法上支援這三要素。如何藉助抽象思維用好三要素特別是多態還是非常困難的,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、看實驗說明裡要求開啟shell,自己還傻傻的在群裡問“案頭上哪有shell”。後來才想起來翻一翻實驗一的記錄,明白了應該開啟Xface,之後系統自動運行shell程式。Linux系統對自己來說相對陌生,不會操作的時候多複習以前的實驗記錄。
2、做UML圖的時候,Animal類的shout()沒有顯示斜體。想想覺得可能是少了哪個步驟,果然是忘記勾選“抽象方法”這一欄了。
四、實驗收穫
1、第一次聽說了測試代碼和TDD。之前學C的時候也明白要對代碼進行白盒、黑箱測試,但是往往這種測試行為是自發的、不系統的,根本沒有記錄,甚至是想到哪裡測試哪裡。而學習了Junit Test Case後,發現這樣的單元測試系統很管用,不僅介面美觀(看到綠條條的時候好開心),而且功能強大,能夠很好地記錄開發人員測試的過程,便於代碼的管理和維護。有時候,花在測試代碼上的時間多於產品代碼,但正因如此,才能確保程式的完整性、健壯性。
2、初步學習了UML圖。UML圖能夠一目瞭然地概括各個類的屬性和功能,輕鬆看出各類之間的關係,方便提取和抽象。聽說UML能和java代碼互相轉化,真是神奇,有待探索。
3、學習了程式設計的SOLID思想。後面三個不是太理解,不過前面兩個圖很形象,並在實際學習JAVA的過程中體會到了SRP、OCP思想。練習題中也有體現。
4、編練習題讓我感受到了是在編JAVA代碼。之前編過的代碼,並沒有怎麼體現“物件導向”的思想,於我而言,只是換了一種文法的C程式。而今天的複數類,讓我體會到了什麼是抽象、封裝,並且第一次、主動使用了static(之前一直沒怎麼想過要用靜態,對各種修飾符也不是很敏感,想到了就用,想不到就不用)
五、練習題
//虛擬碼
類有虛部實部
複數的加法運算
複數的減法運算
複數的乘法運算
複數的除法運算
列印一個複數
列印四則運算的語句
public class ComplexDemo {
public static void main(String[] args) {
Complex x = new Complex(1.0 , -2.0);
Complex y = new Complex(3.0 , 4.0);
Complex.printSentence(x, y);
}
}
class Complex
{
private double a,b;
Complex(double a,double b)//構造方法對複數進行初始化
{
this.a = a;
this.b = b;
}
static Complex Add(Complex x,Complex y)
{
return new Complex(x.a+y.a, x.b+y.b);
}
static Complex Minus(Complex x,Complex y)
{
return new Complex(x.a-y.a, x.b-y.b);
}
static Complex Multiple(Complex x,Complex y)
{
return new Complex(x.a * y.a - x.b * y.b, x.a * y.b + x.b * y.a);
}
static Complex Divide(Complex x,Complex y)
{
Complex conjugate = new Complex(y.a, -y.b); //求出除數y的共軛複數
double mo = (y.a)*(y.a) + (y.b)*(y.b); //計算y的模
Complex t = Multiple(x,conjugate);
return new Complex(t.a/mo , t.b/mo);
}
static String print(Complex x)
{
if (x.b > 0)
return x.a + "+" + x.b + "i";
else
return x.a + "-" + (-x.b) + "i";
}
static void printSentence(Complex x, Complex y)
{
System.out.println("("+ print(x) + ")+("+ print(y) + ") =" +print(Add(x, y)));
System.out.println("("+ print(x) + ")-("+ print(y) + ") =" +print(Minus(x, y)));
System.out.println("("+ print(x) + ")*("+ print(y) + ") =" +print(Multiple(x, y)));
System.out.println("("+ print(x) + ")/("+ print(y) + ") =" +print(Divide(x, y)));
}
}
構造方法的使用:利用構造方法一載入就啟動並執行特點,給複數初始化。
返回一個對象:一開始想直接列印x.a+"+"+x.b+"i",後來發現return new Complex(x.a+y.a, x.b+y.b);這樣的語句更有閱讀性,也方便維護
分工:複數類的四種運算方法各司其職,對外提供介面(傳回值),內部運算過程是封裝的。考慮到SRP單一職責原則,放棄了在四則運算方法中列印語句的功能
提取:列印一個複數的過程要多次使用,可以提取,符合DRY原則
封裝:一開始也想過在主函數中調用對象的print(Add(x,y))輸出語句功能,後來覺得違反了OCP開放-封閉原則,因為暴露了類內部的print方法和Add方法。最終把四種列印語句封裝為一個函數,叫printSentence(Complex x, Complex y),又因為該方法涉及兩個對象,不適合用一個對象來調用,所以想到用類名調用,於是靜態,有關的方法統統都靜態了。
運行結果:
六、時間統計
步驟 |
耗時 |
百分比 |
需求分析 |
3min |
3.2% |
設計 |
10min |
10.8% |
代碼實現 |
50min |
53.8% |
測試 |
20min |
21.5% |
分析總結 |
10min |
10.8% |
JAVA實驗二(物件導向)