相信看到這篇文字的人已經不須要了解什麼是接口了,我就再也不過多的作介紹了,直接步入正題,接口測試如何編寫。那麼在這一篇裏,咱們用一個例子,讓各位對這個重要的編程思想有個直觀的印象。爲充分考慮到初學者,因此這個例子很是簡單,望各位高手見諒。html
爲了擺脫新手的概念,我這裏也儘可能不用main方法,而採用testNG編寫測試用例。編程
定義:如今咱們要開發一個應用,模擬移動存儲設備的讀寫,即計算機與U盤、MP三、移動硬盤等設備進行數據交換。設計模式
上下文(環境):已知要實現U盤、MP3播放器、移動硬盤三種移動存儲設備,要求計算機能同這三種設備進行數據交換,而且之後可能會有新的第三方的移動存儲設備,因此計算機必須有擴展性,能與目前未知而之後可能會出現的存儲設備進行數據交換。各個存儲設備間讀、寫的實現方法不一樣,U盤和移動硬盤只有這兩個方法,MP3Player還有一個PlayMusic方法。ide
名詞定義:數據交換={讀,寫}測試
解決方案列舉this
方案一:分別定義FlashDisk、MP3Player、MobileHardDisk三個類,實現各自的Read和Write方法。而後在Computer類中實例化上述三個類,爲每一個類分別寫讀、寫方法。例如,爲FlashDisk寫ReadFromFlashDisk、WriteToFlashDisk兩個方法。總共六個方法。編碼
方案二:定義抽象類MobileStorage,在裏面寫虛方法Read和Write,三個存儲設備繼承此抽象類,並重寫Read和Write方法。Computer類中包含一個類型爲MobileStorage的成員變量,併爲其編寫get/set器,這樣Computer中只須要兩個方法:ReadData和WriteData,並經過多態性實現不一樣移動設備的讀寫。spa
方案三:與方案二基本相同,只是不定義抽象類,而是定義接口IMobileStorage,移動存儲器類實現此接口。Computer中經過依賴接口IMobileStorage實現多態性。.net
方案四:定義接口IReadable和IWritable,兩個接口分別只包含Read和Write,而後定義接口IMobileStorage接口繼承自IReadable和IWritable,剩下的實現與方案三相同。插件
下面,咱們來分析一下以上四種方案:
首先,方案一最直白,實現起來最簡單,可是它有一個致命的弱點:可擴展性差。或者說,不符合「開放-關閉原則」(注:意爲對擴展開放,對修改關閉)。當未來有了第三方擴展移動存儲設備時,必須對Computer進行修改。這就如在一個真實的計算機上,爲每一種移動存儲設備實現一個不一樣的插口、並分別有各自的驅動程序。當有了一種新的移動存儲設備後,咱們就要將計算機大卸八塊,而後增長一個新的插口,在編寫一套針對此新設備的驅動程序。這種設計顯然不可取。
此方案的另外一個缺點在於,冗餘代碼多。若是有100種移動存儲,那咱們的Computer中豈不是要至少寫200個方法,這是不能接受的!
再看 方案二和方案三,之因此將這兩個方案放在一塊兒討論,是由於他們基本是一個方案(從思想層面上來講),只不過實現手段不一樣,一個是使用了抽象類,一個是使用了接口,並且最終達到的目的應該是同樣的。
咱們先來評價這種方案:首先它解決了代碼冗餘的問題,由於能夠動態替換移動設備,而且都實現了共同的接口,因此無論有多少種移動設備,只要一個Read方法和一個Write方法,多態性就幫咱們解決問題了。而對第一個問題,因爲能夠運行時動態替換,而沒必要將移動存儲類硬編碼在Computer中,因此有了新的第三方設備,徹底能夠替換進去運行。這就是所謂的「依賴接口,而不是依賴與具體類」,不信你看看,Computer類只有一個MobileStorage類型或IMobileStorage類型的成員變量,至於這個變量具體是什麼類型,它並不知道,這取決於咱們在運行時給這個變量的賦值。如此一來,Computer和移動存儲器類的耦合度大大降低。
那麼 這裏該選抽象類仍是接口呢?還記得第一篇文章我對抽象類和接口選擇的建議嗎?看動機。這裏,咱們的動機顯然是實現多態性而不是爲了代碼複用,因此固然要用接口。
最後 咱們再來看一看方案四,它和方案三很相似,只是將「可讀」和「可寫」兩個規則分別抽象成了接口,而後讓IMobileStorage再繼承它們。這樣作,顯然進一步提升了靈活性,可是,這有沒有設計過分的嫌疑呢?個人觀點是:這要看具體狀況。若是咱們的應用中可能會出現一些類,這些類只實現讀方法或只實現寫方法,如只讀光盤,那麼這樣作也是能夠的。若是咱們知道之後出現的東西都是能讀又能寫的,那這兩個接口就沒有必要了。其實若是將只讀設備的Write方法留空或拋出異常,也能夠不要這兩個接口。總之一句話:理論是死的,人是活的,一切從現實須要來,防止設計不足,也要防止設計過分。
在這裏,咱們姑且認爲之後的移動存儲都是能讀又能寫的,因此咱們選方案三。
實現
下面,咱們要將解決方案加以實現。我選擇的語言是Java,因此使用其餘語言的朋友同樣能夠參考。
首先編寫IMobileStorage接口:
Code:IMobileStorage
1 public interface IMobileStorage { 2 3 void Read(); // 讀取數據 4 void Write(); // 寫入數據 5 6 }
代碼比較簡單,只有兩個方法,沒什麼好說的,接下來是三個移動存儲設備的具體實現代碼:
U盤
Code:FlashDisk
1 public class FlashDisk implements IMobileStorage{ 2 @Override 3 public void Read() { 4 System.out.println("Reading from FlashDisk……"); 5 System.out.println("Read finished!"); 6 } 7 8 @Override 9 public void Write() { 10 System.out.println("Writing to FlashDisk……"); 11 System.out.println("Write finished!"); 12 } 13 }
MP3
Code:MP3Player
public class MP3Player implements IMobileStorage{ @Override public void Read() { System.out.println("Reading from MP3Player……"); System.out.println("Read finished!"); } @Override public void Write() { System.out.println("Writing to MP3Player……"); System.out.println("Write finished!"); } public void PlayMusic(){ System.out.println("Music is playing……"); } }
移動硬盤
Code:MobileHardDisk
public class MobileHardDisk implements IMobileStorage{ @Override public void Read() { System.out.println("Reading from MobileHardDisk……"); System.out.println("Read finished!"); } @Override public void Write() { System.out.println("Writing to MobileHardDisk……"); System.out.println("Write finished!"); } }
能夠看到,它們都實現了IMobileStorage接口,並重寫了各自不一樣的Read和Write方法。下面,咱們來寫Computer:
Code:Computer
public class Computer { private IMobileStorage _usbDrive; public IMobileStorage get_usbDrive() { return _usbDrive; } public void set_usbDrive(IMobileStorage _usbDrive) { this._usbDrive = _usbDrive; } public Computer(){} public Computer(IMobileStorage _usbDrive) { this._usbDrive = _usbDrive; } public void ReadData(){ this._usbDrive.Read(); } public void WriteData(){ this._usbDrive.Write(); } }
其中的UsbDrive就是可替換的移動存儲設備,之因此用這個名字,是爲了讓你們以爲直觀,就像咱們日常使用電腦上的USB插口插拔設備同樣。
OK!下面咱們來測試咱們的「電腦」和「移動存儲設備」是否工做正常。我是用的Java控制檯程序打印結果,具體代碼以下:
Code:測試代碼
public class ToTest { @Test public void program1(){ Computer computer = new Computer(); IMobileStorage mp3Player = new MP3Player(); IMobileStorage flashDisk = new FlashDisk(); IMobileStorage moblieHardDisk = new MobileHardDisk(); System.out.println("I inserted my MP3 Player into my computer and copy some music to it:"); computer.set_usbDrive(mp3Player); computer.WriteData(); System.out.println("===================="); System.out.println("Well,I also want to copy a great movie to my computer from a mobile hard disk:"); computer.set_usbDrive(moblieHardDisk); computer.ReadData(); System.out.println("===================="); System.out.println("OK!I have to read some files from my flash disk and copy another file to it:"); computer.set_usbDrive(flashDisk); computer.ReadData(); computer.WriteData(); System.out.println(); }
運行結果以下:
圖2.1 各類移動存儲設備測試結果
好的,看來咱們的系統工做良好。
後來……
剛過了一個星期,就有人送來了新的移動存儲設備NewMobileStorage,讓我測試能不能用,我微微一笑,心想這不是小菜一碟,讓咱們看看面向接口編程的威力吧!將測試程序修改爲以下:
(NewMobileStorage的類請參照u盤、移動硬盤等類編寫……也能夠自創)
測試代碼
@Test public void program2(){ Computer computer = new Computer(); IMobileStorage newMobileStorage = new NewMoblieStorage(); computer.set_usbDrive(newMobileStorage); newMobileStorage.Write(); newMobileStorage.Read(); }
運行結果:
圖2.2 新設備擴展測試結果
又過了幾天,有人通知我說又有一個叫SuperStorage的移動設備要接到咱們的Computer上,我心想來吧,管你是「超級存儲」仍是「特級存儲」,個人「面向接口編程大法」把大家通通搞定。
可是,當設備真的送來,我傻眼了,開發這個新設備的團隊沒有拿到咱們的IMobileStorage接口,天然也沒有遵守這個約定。這個設備的讀、寫方法不叫Read和Write,而是叫rd和wt,這下完了……不符合接口啊,插不上。可是,不要着急,咱們回到現實來找找解決的辦法。咱們一塊兒想一想:若是你的Computer上只有USB接口,而有人拿來一個PS/2的鼠標要插上用,你該怎麼辦?想起來了吧,是否是有一種叫「PS/2-USB」轉換器的東西?也叫適配器,能夠進行不一樣接口的轉換。對了!程序中也有轉換器。
這裏,我要引入一個設計模式,叫「Adapter」。它的做用就如現實中的適配器同樣,把接口不一致的兩個插件接合起來。因爲本篇不是講設計模式的,並且Adapter設計模式很好理解,因此我就不細講了,先來看我設計的類圖吧:
如圖所示,雖然SuperStorage沒有實現IMobileStorage,但咱們定義了一個實現IMobileStorage的SuperStorageAdapter,它聚合了一個SuperStorage,並將rd和wt適配爲Read和Write,SuperStorageAdapter(這裏注意自行編寫SuperStorage的類和他用到的接口)
圖2.3 Adapter模式應用示意
具體代碼以下:
Code:SuperStorageAdapter
1 public class SuperStorageAdapter implements IMobileStorage { 2 private SuperStorage _superStorage; 3 4 public SuperStorage get_superStorage() { 5 return _superStorage; 6 } 7 8 public void set_superStorage(SuperStorage _superStorage) { 9 this._superStorage = _superStorage; 10 } 11 12 @Override 13 public void Read(){ 14 this._superStorage.rd(); 15 } 16 17 @Override 18 public void Write() { 19 this._superStorage.wt(); 20 } 21 }
好,如今咱們來測試適配過的新設備,測試代碼以下:
Code:測試代碼
@Test public void program3(){ Computer computer = new Computer(); SuperStorageAdapter superStorageAdapter = new SuperStorageAdapter(); SuperStorage superStorage = new SuperStorage(); superStorageAdapter.set_superStorage(superStorage); System.out.println("Now,I am testing the new super storage with adapter:"); computer.set_usbDrive(superStorageAdapter); computer.ReadData(); computer.WriteData(); System.out.println(); }
運行結果:
圖2.4 利用Adapter模式運行新設備測試結果
OK!雖然遇到了一些困難,不過在設計模式的幫助下,咱們仍是在沒有修改Computer任何代碼的狀況下實現了新設備的運行。但願各位朋友結合第一篇的理論和這個例子,仔細思考面向接口的問題。固然,不要忘告終合現實。
轉載自:https://www.cnblogs.com/iceb/p/7093884.html