實驗二《Java面向對象程序設計》實驗報告
實驗內容
- 初步掌握單元測試和TDD
- 理解並掌握面向對象三要素:封裝、繼承、多態
- 初步掌握UML建模
- 熟悉S.O.L.I.D原則
- 了解設計模式
實驗要求
-
沒有Linux基礎的同學建議先學習《Linux基礎入門(新版)》《Vim編輯器》 課程
-
完成實驗、撰寫實驗報告,實驗報告以博客方式發表在博客園,注意實驗報告重點是運行結果,遇到的問題(工具查找,安裝,使用,程序的編輯,調試,運行等)、解決辦法(空洞的方法如“查網絡”、“問同學”、“看書”等一律得0分)以及分析(從中可以得到什么啟示,有什么收獲,教訓等)。報告可以參考范飛龍老師的指導
-
嚴禁抄襲,有該行為者實驗成績歸零,並附加其他懲罰措施。
-
請大家先在實驗樓中的~/Code目錄中用自己的學號建立一個目錄,代碼和UML圖要放到這個目錄中,截圖中沒有學號的會要求重做,然后跟着下面的步驟練習。
實驗步驟
(一)單元測試
(1)三種代碼
- 偽代碼:拿到一個問題,不要直接動手編程序。要先構思框架——也就是我們所說的寫偽代碼,把解決問題的步驟用我們平時的語言寫出來。
- 產品代碼:真正用來實現產品的代碼,把構思出來的偽代碼用編程語言實現。
- 測試代碼:測試自己的產品代碼是否有漏洞,並根據漏洞修改、調整產品代碼。
- 實驗步驟:
- 新建
主類名+Test.class
:點擊主類名——>Ctrl+Enter
——>Creat Test
- 新建test文件夾:右鍵項目名——>New——>Directory
- 配置JUnit:Fire——>Project Structure——>Modules——>Dependencies——>綠色加號選第一個——>選中如圖所示兩個文件,一路OK選中就能配置好啦~
- 新建
- 運行結果截圖
(2)TDD(Test Driven Devlopment, 測試驅動開發)
- TDD的一般步驟如下:
- 明確當前要完成的功能,記錄成一個測試列表
- 快速完成編寫針對此功能的測試用例
- 編寫產品代碼
- 測試通過
- 對代碼進行重構,並保證測試通過(重構下次實驗練習)
- 循環完成所有功能的開發
- TDD的編碼節奏
- 增加測試代碼,JUnit出現紅條
- 修改產品代碼
- JUnit出現綠條,任務完成
- 實驗步驟:先編寫測試代碼,再根據偽代碼和測試代碼編寫產品代碼。並在IDEA中使用Junit進行單元測試,出現綠條則測試通過
- 運行結果截圖
(二)面向對象三要素
- 抽象
抽象就是抽出事物的本質特征而暫時不考慮他們的細節。對於復雜系統問題人們借助分層次抽象的方法進行問題求解;在抽象的最高層,可以使用問題環境的語言,以概括的方式敘述問題的解。在抽象的較低層,則采用過程化的方式進行描述。在描述問題解時,使用面向問題和面向實現的術語。程序設計中,抽象包括兩個方面,一是過程抽象,二是數據抽象 - 封裝、繼承與多態
面向對象(Object-Oriented)的三要素包括:封裝、繼承、多態。
面向對象的思想涉及到軟件開發的各個方面,如面向對象分析(OOA)、面向對象設計(OOD)、面向對象編程實現(OOP)。 - 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類進行擴充,讓其支持Float類
- 實驗代碼:
import java.util.Objects;
abstract class Data {
abstract public void DisplayValue();
}
class Integer extends Data {
int value;
Integer() {
value=100;
}
public void DisplayValue(){
System.out.println (value);
}
}
class Long extends Data {
long value;
Long() {
value=2147483647;
}
public void DisplayValue(){
System.out.println (value);
}
}
class Float extends Data {
float value;
Float() {
value=(float)20165322.0;
}
public void DisplayValue(){
System.out.println (value);
}
}
// Pattern Classes
abstract class Factory {
abstract public Data CreateDataObject();
}
class IntFactory extends Factory {
public Data CreateDataObject(){
return new Integer();
}
}
class LongFactory extends Factory {
public Data CreateDataObject(){
return new Long();
}
}
class FloatFactory extends Factory {
public Data CreateDataObject(){
return new Float();
}
}
//Client classes
class Document {
Data data;
Document(Factory factory){
data = factory.CreateDataObject();
}
public void DisplayData(){
data.DisplayValue();
}
}
public class MyDoc {
static Document d;
MyDoc(Document d) {
this.d = d;
}
public static void main(String[] args) {
d = new Document(new FloatFactory());
d.DisplayData();
}
}
- 運行結果截圖:
(三)使用TDD的方式設計關實現復數類Complex
- 產品代碼:
public class Complex {
// 定義屬性並生成getter,setter
double RealPart;
double ImagePart;
// 定義構造函數
public Complex(){
RealPart = 0;
ImagePart = 1;
}
public Complex(double R,double I){
ImagePart = I;
RealPart = R;
}
//Override Object
public boolean equals(Object obj){
if(this == obj) {
return true;
}
if(!(obj instanceof Complex)) {
return false;
}
Complex complex = (Complex) obj;
if(complex.RealPart != ((Complex) obj).RealPart) {
return false;
}
if(complex.ImagePart != ((Complex) obj).ImagePart) {
return false;
}
return true;
}
public String toString() {
String string = "";
if (ImagePart > 0)
string = RealPart + "+" + ImagePart + "i";
if (ImagePart == 0)
string = RealPart + "";
if (ImagePart < 0)
string = RealPart + " " + ImagePart + "i";
return string;
}
// 定義公有方法:加減乘除
Complex ComplexAdd(Complex a) {
return new Complex(RealPart+a.RealPart,ImagePart+a.ImagePart);
}
Complex ComplexSub(Complex a) {
return new Complex(RealPart-a.RealPart,ImagePart-a.ImagePart);
}
Complex ComplexMulti(Complex a) {
return new Complex(RealPart*a.RealPart,ImagePart*a.ImagePart);
}
Complex ComplexDiv(Complex a) {
if(a.RealPart==0||a.ImagePart==0) {
System.out.println("被減數不能為0");
return new Complex();
}
double d = Math.sqrt(a.RealPart*a.RealPart)+Math.sqrt(a.ImagePart*a.ImagePart);
return new Complex((RealPart*a.RealPart+ImagePart*a.ImagePart)/d,Math.round((RealPart*a.ImagePart-ImagePart*a.RealPart)/d));
}
}
- 測試代碼
import static org.junit.Assert.*;
import org.junit.Test;
import junit.framework.TestCase;
public class ComplexTest extends TestCase {
Complex complex = new Complex(1,1);
@Test
public void testAdd(){
assertEquals(new Complex(3.3,3.4), complex.ComplexAdd(new Complex(2.3,2.4)));
}
//測試加法
@Test
public void testSub(){
assertEquals(new Complex(-5.3,-2.4), complex.ComplexSub(new Complex(6.3,3.4)));
}
//測試減法
@Test
public void testMulti(){
assertEquals(new Complex(3.0,2.0), complex.ComplexMulti(new Complex(3.0,2.0)));
}
//測試乘法
@Test
public void testDiv(){
assertEquals(new Complex(1.0,1.0), complex.ComplexDiv(new Complex(1.0,1.0)));
assertEquals(new Complex(0.0,0.0), complex.ComplexDiv(new Complex(1.0,0.0)));
//assertEquals(new Complex(0.0,0.0), complex.ComplexDiv(new Complex(3,4)));
//邊緣測試
}
@Test
public void testequals(){
assertEquals(true, complex.equals(new Complex(1.0,1.0)));
}
//測試判斷相等
}
- 運行結果截圖
(四)使用StarUML對實驗二中的代碼進行建模
- 參考starUML教程
- 建模如下
實驗總結
學習了測試代碼的使用以及TDD的模式,但還不夠熟練,基本上是參照老師的教程去做的。接下來要更多的練習,爭取在大創中能編寫較為全面的優秀的測試代碼供其他成員編寫算法。