設計模式-適配器模式(Go語言描述)

在上一篇博客設計模式-策略模式(Go語言描述)中我們用最簡單的代碼用go語言描述了設計模式中的策略模式,用最簡單的實例來描述相信可以讓初學者可以很輕鬆的掌握各種設計模式。繼上篇博客,我們接着用同樣簡單的代碼來了解一下適配器模式。

適配器模式介紹

說起適配器模式,相信很多做android的同學第一印象就是AdapterView的Adapter,那它是幹嘛用的呢?爲什麼要叫adapter呢?要了解這個問題,我們首先來看看適配器模式的定義:

將一個類的接口轉換成客戶希望的另外一個接口。適配器模式使得原本由於接口不兼容而不能一起工作的那些類可以一起工作。——Gang of Four

恩,看起來好像有點迷糊,舉個例子吧:

我電腦的電源是三個插頭(也就是有地線)的那種,不知道爲啥學校的插座都是兩個插孔的,哎呀,這可咋辦啊!同學建議我們買個轉換器,這種轉換器有三個插孔,我的電源可以插進去,同時它還有兩個插頭,可以插進學校的插座裏,嘿嘿,同學真聰明,這麼容易的就解決了我的問題。

在上面的例子裏,那個轉換器也可以叫做適配器,我們現在要說的適配器模式靈感就是來自上述所述的實際生活中遇到的問題。那在我們程序設計中會遇到什麼樣的問題呢? 再來看個例子:

應老師的要求,我們現在需要做一個音樂播放器,現在我算是知道一點面向對象的原則了,所以我首先設計了一個接口,這個接口有一個playMusic的方法,接着我很輕鬆的利用這個接口設計出了一個音樂播放器,音樂控制器通過調用playMusic可以完美的播放任何音樂,嘖嘖嘖,高興中…老師對我的音樂播放器也很滿意,不過他又提出了新的需求,讓我的音樂播放器也可以播放遊戲的聲音,並給了我一個播放遊戲聲音的類,這個類也很簡單,只有一個playSound方法,雖然很簡單,但是現在我困惑了,因爲我設計的音樂控制器只認識playMusic而不認識playSound,難道我要重新設計我的音樂控制器嗎?正當我苦惱的時候,同學出現在了我身後,輕聲的告訴我:“適配器模式可以完美的解決你的問題,你只需要寫一個Adapter實現你的音樂播放接口,在這個Adapter的playMusic中去調用遊戲聲音播放器的playSound方法就可以了。”聽了同學的話,我突然恍然大悟,原來這就是適配器模式!

好了,通過上面的三個小段子,相信大家對適配器模式應該了有了大概的認識,下面還是用一張結構圖來清晰的描述一下什麼是適配器模式吧。

通過上面的圖我們也可以看出來,適配器要做的事情就是讓我們寫的野實現適配到系統需要的標準實現上。下面我們迅速進去代碼模式,讓代碼告訴我們適配器模式張啥樣!

代碼實現

代碼實現環節,我們還是用上面那個音樂播放器的例子,首先設計一個音樂播放的接口:

package player

type Player interface {
    PlayMusic()
}

這個接口只有一個方法PlayMusic,系統通過調用PlayMusic這個方法達到播放音樂的目的。 在來看看我們播放音樂的實現。

package player
import "fmt"

type MusicPlayer struct {
    Src string
}

func (p MusicPlayer) PlayMusic() {
    fmt.Println("play music: " + p.Src)
}

MusicPlayer有一個方法是PlayMusic(),所以它實現了Player接口,來讓我們的音樂播放器播放器來吧,

package main
import . "./player"

func main() {
    var player Player = MusicPlayer {Src:"music.mp3"}
    play(player)
}

func play(player Player) {
    player.PlayMusic()
}

代碼也超級簡單,一個play方法去調用了Player的實現的PlayMusic方法。來看看結果,

現在我們的音樂播放器可以播放歌曲了,只需要給出一個歌曲的路徑就ok,不過現在我們還需要播放遊戲聲音,並且給了我們一個這樣的實現。

package player
import "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 player

type GameSoundAdapter struct {
    SoundPlayer GameSoundPlayer
}

func (p GameSoundAdapter) PlayMusic() {
    p.SoundPlayer.PlaySound()
}

GameSoundAdapter有一個GameSoundPlayer類型的屬性,它就是我們上面的那個遊戲聲音播放器,GameSoundPlayer還有一個方法名字叫PlayMusic,所以GameSoundPlayer實現了Player接口,我們可以把它用於player方法中,在PlayMusic中我們是調用的GameSoundPlayerPlaySound來播放聲音的。
來看看我們這個適配器適配的咋樣,

package main
import . "./player"

func main() {
    gameSound := GameSoundPlayer {Src:"game.mid"}
    gameAdapter := GameSoundAdapter {SoundPlayer:gameSound}
    play(gameAdapter)
}

func play(player Player) {
    player.PlayMusic()
}

看main函數中,首先我們還是有一個GameSoundPlayer類型的變量,然後將它賦值給了GameSoundAdapterSoundPlayer屬性,下面調用GameSoundAdapterPlayMusic方法,就可以間接的調用GameSoundPlayerPlaySound方法了,這樣我們就輕鬆的將GameSoundPlayer適配到了Player
來看看結果:

整體來看我們的代碼還是很簡單,不過簡單的代碼已經將適配器模式講解的很清楚了,那最後我們來思考一個問題,適配器模式體現了哪些面向對象的設計原則呢?針對接口編程有木有? 開閉原則有木有?

好了,適配器模式我們就說到這裏,最後是文章的實例代碼下載:http://download.csdn.net/detail/qibin0506/9420484

發佈了82 篇原創文章 · 獲贊 782 · 訪問量 85萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章