面向接口編程詳解(二)——編程實例_第1頁
面向接口編程詳解(二)——編程實例_第2頁
面向接口編程詳解(二)——編程實例_第3頁
面向接口編程詳解(二)——編程實例_第4頁
面向接口編程詳解(二)——編程實例_第5頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

1、面向接口編程詳解(二)編程實例2008-04-11 15:49 by EricZhang(T2噬菌體), 11423 visits, 網(wǎng)摘, 收藏, 編輯 通過上一篇文章的討論,我想各位朋友對“面接接口編程”有了一個大致的了解。那么在這一篇里,我們用一個例子,讓各位對這個重要的編程思想有個直觀的印象。為充分考慮到初學者,所以這個例子非常簡單,望各位高手見諒。問題的提出 定義:現(xiàn)在我們要開發(fā)一個應用,模擬移動存儲設備的讀寫,即計算機與U盤、MP3、移動硬盤等設備進行數(shù)據(jù)交換。上下文(環(huán)境):已知要實現(xiàn)U盤、MP3播放器、移動硬盤三種移動存儲設備,要求計算機能同這三種設備進行數(shù)據(jù)交換,并且以后可能

2、會有新的第三方的移動存儲設備,所以計算機必須有擴展性,能與目前未知而以后可能會出現(xiàn)的存儲設備進行數(shù)據(jù)交換。各個存儲設備間讀、寫的實現(xiàn)方法不同,U盤和移動硬盤只有這兩個方法,MP3Player還有一個PlayMusic方法。名詞定義:數(shù)據(jù)交換=讀,寫看到上面的問題,我想各位腦子中一定有了不少想法,這是個很好解決的問題,很多方案都能達到效果。下面,我列舉幾個典型的方案。解決方案列舉 方案一:分別定義FlashDisk、MP3Player、MobileHardDisk三個類,實現(xiàn)各自的Read和Write方法。然后在Computer類中實例化上述三個類,為每個類分別寫讀、寫方法。例如,為FlashD

3、isk寫ReadFromFlashDisk、WriteToFlashDisk兩個方法??偣擦鶄€方法。方案二:定義抽象類MobileStorage,在里面寫虛方法Read和Write,三個存儲設備繼承此抽象類,并重寫Read和Write方法。Computer類中包含一個類型為MobileStorage的成員變量,并為其編寫get/set器,這樣Computer中只需要兩個方法:ReadData和WriteData,并通過多態(tài)性實現(xiàn)不同移動設備的讀寫。方案三:與方案二基本相同,只是不定義抽象類,而是定義接口IMobileStorage,移動存儲器類實現(xiàn)此接口。Computer中通過依賴接口IMob

4、ileStorage實現(xiàn)多態(tài)性。方案四:定義接口IReadable和IWritable,兩個接口分別只包含Read和Write,然后定義接口IMobileStorage接口繼承自IReadable和IWritable,剩下的實現(xiàn)與方案三相同。下面,我們來分析一下以上四種方案:首先,方案一最直白,實現(xiàn)起來最簡單,但是它有一個致命的弱點:可擴展性差?;蛘哒f,不符合“開放-關閉原則”(注:意為對擴展開放,對修改關閉)。當將來有了第三方擴展移動存儲設備時,必須對Computer進行修改。這就如在一個真實的計算機上,為每一種移動存儲設備實現(xiàn)一個不同的插口、并分別有各自的驅(qū)動程序。當有了一種新的移動存儲設

5、備后,我們就要將計算機大卸八塊,然后增加一個新的插口,在編寫一套針對此新設備的驅(qū)動程序。這種設計顯然不可取。此方案的另一個缺點在于,冗余代碼多。如果有100種移動存儲,那我們的Computer中豈不是要至少寫200個方法,這是不能接受的!我們再來看方案二和方案三,之所以將這兩個方案放在一起討論,是因為他們基本是一個方案(從思想層面上來說),只不過實現(xiàn)手段不同,一個是使用了抽象類,一個是使用了接口,而且最終達到的目的應該是一樣的。我們先來評價這種方案:首先它解決了代碼冗余的問題,因為可以動態(tài)替換移動設備,并且都實現(xiàn)了共同的接口,所以不管有多少種移動設備,只要一個Read方法和一個Write方法,

6、多態(tài)性就幫我們解決問題了。而對第一個問題,由于可以運行時動態(tài)替換,而不必將移動存儲類硬編碼在Computer中,所以有了新的第三方設備,完全可以替換進去運行。這就是所謂的“依賴接口,而不是依賴與具體類”,不信你看看,Computer類只有一個MobileStorage類型或IMobileStorage類型的成員變量,至于這個變量具體是什么類型,它并不知道,這取決于我們在運行時給這個變量的賦值。如此一來,Computer和移動存儲器類的耦合度大大下降。那么這里該選抽象類還是接口呢?還記得第一篇文章我對抽象類和接口選擇的建議嗎?看動機。這里,我們的動機顯然是實現(xiàn)多態(tài)性而不是為了代碼復用,所以當然要

7、用接口。最后我們再來看一看方案四,它和方案三很類似,只是將“可讀”和“可寫”兩個規(guī)則分別抽象成了接口,然后讓IMobileStorage再繼承它們。這樣做,顯然進一步提高了靈活性,但是,這有沒有設計過度的嫌疑呢?我的觀點是:這要看具體情況。如果我們的應用中可能會出現(xiàn)一些類,這些類只實現(xiàn)讀方法或只實現(xiàn)寫方法,如只讀光盤,那么這樣做也是可以的。如果我們知道以后出現(xiàn)的東西都是能讀又能寫的,那這兩個接口就沒有必要了。其實如果將只讀設備的Write方法留空或拋出異常,也可以不要這兩個接口。總之一句話:理論是死的,人是活的,一切從現(xiàn)實需要來,防止設計不足,也要防止設計過度。在這里,我們姑且認為以后的移動存

8、儲都是能讀又能寫的,所以我們選方案三。實現(xiàn) 下面,我們要將解決方案加以實現(xiàn)。我選擇的語言是C#,但是在代碼中不會用到C#特有的性質(zhì),所以使用其他語言的朋友一樣可以參考。首先編寫IMobileStorage接口:Code:IMobileStorage1namespaceInterfaceExample23publicinterfaceIMobileStorage45voidRead();/從自身讀數(shù)據(jù)6voidWrite();/將數(shù)據(jù)寫入自身78代碼比較簡單,只有兩個方法,沒什么好說的,接下來是三個移動存儲設備的具體實現(xiàn)代碼:U盤Code:FlashDisk1namespaceInterface

9、Example23publicclassFlashDisk:IMobileStorage45publicvoidRead()67Console.WriteLine(ReadingfromFlashDisk);8Console.WriteLine(Readfinished!);91011publicvoidWrite()1213Console.WriteLine(WritingtoFlashDisk);14Console.WriteLine(Writefinished!);151617MP3Code:MP3Player1namespaceInterfaceExample23publicclass

10、MP3Player:IMobileStorage45publicvoidRead()67Console.WriteLine(ReadingfromMP3Player);8Console.WriteLine(Readfinished!);91011publicvoidWrite()1213Console.WriteLine(WritingtoMP3Player);14Console.WriteLine(Writefinished!);151617publicvoidPlayMusic()1819Console.WriteLine(Musicisplaying);202122移動硬盤Code:Mo

11、bileHardDisk1namespaceInterfaceExample23publicclassMobileHardDisk:IMobileStorage45publicvoidRead()67Console.WriteLine(ReadingfromMobileHardDisk);8Console.WriteLine(Readfinished!);91011publicvoidWrite()1213Console.WriteLine(WritingtoMobileHardDisk);14Console.WriteLine(Writefinished!);151617可以看到,它們都實現(xiàn)

12、了IMobileStorage接口,并重寫了各自不同的Read和Write方法。下面,我們來寫Computer:Code:Computer1namespaceInterfaceExample23publicclassComputer45privateIMobileStorage_usbDrive;67publicIMobileStorageUsbDrive89get1011returnthis._usbDrive;1213set1415this._usbDrive=value;16171819publicComputer()20212223publicComputer(IMobileStora

13、geusbDrive)2425this.UsbDrive=usbDrive;262728publicvoidReadData()2930this._usbDrive.Read();313233publicvoidWriteData()3435this._usbDrive.Write();363738其中的UsbDrive就是可替換的移動存儲設備,之所以用這個名字,是為了讓大家覺得直觀,就像我們平常使用電腦上的USB插口插拔設備一樣。OK!下面我們來測試我們的“電腦”和“移動存儲設備”是否工作正常。我是用的C#控制臺程序,具體代碼如下:Code:測試代碼1namespaceInterfaceEx

14、ample23classProgram45staticvoidMain(stringargs)67Computercomputer=newComputer();8IMobileStoragemp3Player=newMP3Player();9IMobileStorageflashDisk=newFlashDisk();10IMobileStoragemobileHardDisk=newMobileHardDisk();1112Console.WriteLine(IinsertedmyMP3Playerintomycomputerandcopysomemusictoit:);13computer

15、.UsbDrive=mp3Player;14computer.WriteData();15Console.WriteLine();1617Console.WriteLine(Well,Ialsowanttocopyagreatmovietomycomputerfromamobileharddisk:);18computer.UsbDrive=mobileHardDisk;19computer.ReadData();20Console.WriteLine();2122Console.WriteLine(OK!Ihavetoreadsomefilesfrommyflashdiskandcopyan

16、otherfiletoit:);23computer.UsbDrive=flashDisk;24computer.ReadData();25computer.WriteData();26Console.ReadLine();272829現(xiàn)在編譯、運行程序,如果沒有問題,將看到如下運行結果:圖2.1 各種移動存儲設備測試結果好的,看來我們的系統(tǒng)工作良好。 后來 剛過了一個星期,就有人送來了新的移動存儲設備NewMobileStorage,讓我測試能不能用,我微微一笑,心想這不是小菜一碟,讓我們看看面向接口編程的威力吧!將測試程序修改成如下:Code:測試代碼1namespaceInterface

17、Example23classProgram45staticvoidMain(stringargs)67Computercomputer=newComputer();8IMobileStoragenewMobileStorage=newNewMobileStorage();910Console.WriteLine(Now,Iamtestingthenewmobilestorage:);11computer.UsbDrive=newMobileStorage;12computer.ReadData();13computer.WriteData();14Console.ReadLine();1516

18、17編譯、運行、看結果:哈哈,神奇吧,Computer一點都不用改動,就可以使新的設備正常運行。這就是所謂“對擴展開放,對修改關閉”。圖2.2 新設備擴展測試結果又過了幾天,有人通知我說又有一個叫SuperStorage的移動設備要接到我們的Computer上,我心想來吧,管你是“超級存儲”還是“特級存儲”,我的“面向接口編程大法”把你們統(tǒng)統(tǒng)搞定。但是,當設備真的送來,我傻眼了,開發(fā)這個新設備的團隊沒有拿到我們的IMobileStorage接口,自然也沒有遵照這個約定。這個設備的讀、寫方法不叫Read和Write,而是叫rd和wt,這下完了不符合接口啊,插不上。但是,不要著急,我們回到現(xiàn)實來找

19、找解決的辦法。我們一起想想:如果你的Computer上只有USB接口,而有人拿來一個PS/2的鼠標要插上用,你該怎么辦?想起來了吧,是不是有一種叫“PS/2-USB”轉(zhuǎn)換器的東西?也叫適配器,可以進行不同接口的轉(zhuǎn)換。對了!程序中也有轉(zhuǎn)換器。這里,我要引入一個設計模式,叫“Adapter”。它的作用就如現(xiàn)實中的適配器一樣,把接口不一致的兩個插件接合起來。由于本篇不是講設計模式的,而且Adapter設計模式很好理解,所以我就不細講了,先來看我設計的類圖吧:如圖所示,雖然SuperStorage沒有實現(xiàn)IMobileStorage,但我們定義了一個實現(xiàn)IMobileStorage的SuperStor

20、ageAdapter,它聚合了一個SuperStorage,并將rd和wt適配為Read和Write,SuperStorageAdapter圖2.3 Adapter模式應用示意具體代碼如下:Code:SuperStorageAdapter1namespaceInterfaceExample23publicclassSuperStorageAdapter:IMobileStorage45privateSuperStorage_superStorage;67publicSuperStorageSuperStorage89get1011returnthis._superStorage;1213set1415this._superStorage=value;16171819publicvoidRead()2021this._superStorage.rd();222324publicvoidWrite()2526this._superStorage.wt();27282

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論