在上一篇部落格設計模式-策略模式(Go語言描述)中我們用最簡單的代碼用go語言描述了設計模式中的策略模式,用最簡單的執行個體來描述相信可以讓初學者可以很輕鬆的掌握各種設計模式。繼上篇部落格,我們接著用同樣簡單的代碼來瞭解一下適配器模式。 適配器模式介紹
說起適配器模式,相信很多做android的同學第一印象就是AdapterView的Adapter,那它是幹嘛用的呢。為什麼要叫adapter呢。要瞭解這個問題,我們首先來看看適配器模式的定義:
將一個類的介面轉換成客戶希望的另外一個介面。適配器模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。——Gang of Four
恩,看起來好像有點迷糊,舉個例子吧:
我電腦的電源是三個插頭(也就是有地線)的那種,不知道為啥學校的插座都是兩個插孔的,哎呀,這可咋辦啊。同學建議我們買個轉換器,這種轉換器有三個插孔,我的電源可以插進去,同時它還有兩個插頭,可以插進學校的插座裡,嘿嘿,同學真聰明,這麼容易的就解決了我的問題。
在上面的例子裡,那個轉換器也可以叫做適配器,我們現在要說的適配器模式靈感就是來自上述所述的實際生活中遇到的問題。那在我們程式設計中會遇到什麼樣的問題呢。 再來看個例子:
應老師的要求,我們現在需要做一個音樂播放器,現在我算是知道一點物件導向的原則了,所以我首先設計了一個介面,這個介面有一個playMusic的方法,接著我很輕鬆的利用這個介面設計出了一個音樂播放器,音樂控制器通過調用playMusic可以完美的播放任何音樂,嘖嘖嘖,高興中…老師對我的音樂播放器也很滿意,不過他又提出了新的需求,讓我的音樂播放器也可以播放遊戲的聲音,並給了我一個播放遊戲聲音的類,這個類也很簡單,只有一個playSound方法,雖然很簡單,但是現在我困惑了,因為我設計的音樂控制器只認識playMusic而不認識playSound,難道我要重新設計我的音樂控制器嗎。正當我苦惱的時候,同學出現在了我身後,輕聲的告訴我:“適配器模式可以完美的解決你的問題,你只需要寫一個Adapter實現你的音樂播放介面,在這個Adapter的playMusic中去調用遊戲聲音播放器的playSound方法就可以了。”聽了同學的話,我突然恍然大悟,原來這就是適配器模式。
好了,通過上面的三個小段子,相信大家對適配器模式應該了有了大概的認識,下面還是用一張結構圖來清晰的描述一下什麼是適配器模式吧。
通過上面的圖我們也可以看出來,適配器要做的事情就是讓我們寫的野實現適配到系統需要的標準實現上。下面我們迅速進去代碼模式,讓代碼告訴我們適配器模式張啥樣。 代碼實現
代碼實現環節,我們還是用上面那個音樂播放器的例子,首先設計一個音樂播放的介面:
package playertype Player interface { PlayMusic()}
這個介面只有一個方法PlayMusic,系統通過調用PlayMusic這個方法達到播放音樂的目的。 在來看看我們播放音樂的實現。
package playerimport "fmt"type MusicPlayer struct { Src string}func (p MusicPlayer) PlayMusic() { fmt.Println("play music: " + p.Src)}
MusicPlayer有一個方法是PlayMusic(),所以它實現了Player介面,來讓我們的音樂播放器播放器來吧,
package mainimport . "./player"func main() { var player Player = MusicPlayer {Src:"music.mp3"} play(player)}func play(player Player) { player.PlayMusic()}
代碼也超級簡單,一個play方法去調用了Player的實現的PlayMusic方法。來看看結果,
現在我們的音樂播放器可以播放歌曲了,只需要給出一個歌曲的路徑就ok,不過現在我們還需要播放遊戲聲音,並且給了我們一個這樣的實現。
package playerimport "fmt"type GameSoundPlayer struct { Src string}func (p GameSoundPlayer) PlaySound() { fmt.Println("play sound: " + p.Src)}
GameSoundPlayer也是有一個Src屬性,也有一個方法,不過這個方法叫PlaySound,並不是我們需要的PlayMusic,那可咋辦呢。別忘了咱們的play方法
需要的是一個Player的實現,並自動調用了PlayMusic方法,下面本節的主角-GameSoundAdapter出場。
package playertype GameSoundAdapter struct { SoundPlayer GameSoundPlayer}func (p GameSoundAdapter) PlayMusic() { p.SoundPlayer.PlaySound()}
GameSoundAdapter有一個GameSoundPlayer類型的屬性,它就是我們上面的那個遊戲聲音播放器,GameSoundPlayer還有一個方法名字叫PlayMusic,所以GameSoundPlayer實現了Player介面,我們可以把它用於player方法中,在PlayMusic中我們是調用的GameSoundPlayer的PlaySound來播放聲音的。
來看看我們這個適配器適配的咋樣,
package mainimport . "./player"func main() { gameSound := GameSoundPlayer {Src:"game.mid"} gameAdapter := GameSoundAdapter {SoundPlayer:gameSound} play(gameAdapter)}func play(player Player) { player.PlayMusic()}
看main函數中,首先我們還是有一個GameSoundPlayer類型的變數,然後將它賦值給了GameSoundAdapter的SoundPlayer屬性,下面調用GameSoundAdapter的PlayMusic方法,就可以間接的調用GameSoundPlayer的PlaySound方法了,這樣我們就輕鬆的將GameSoundPlayer適配到了Player。
來看看結果:
整體來看我們的代碼還是很簡單,不過簡單的代碼已經將適配器模式講解的很清楚了,那最後我們來思考一個問題,適配器模式體現了哪些物件導向的設計原則呢。針對介面編程有木有。 開閉原則有木有。
好了,適配器模式我們就說到這裡,最後是文章的執行個體代碼下載:http://download.csdn.net/detail/qibin0506/9420484