在上一篇博客设计模式-策略模式(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
中我们是调用的GameSoundPlayer
的PlaySound
来播放声音的。
来看看我们这个适配器适配的咋样,
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
类型的变量,然后将它赋值给了GameSoundAdapter
的SoundPlayer
属性,下面调用GameSoundAdapter
的PlayMusic
方法,就可以间接的调用GameSoundPlayer
的PlaySound
方法了,这样我们就轻松的将GameSoundPlayer
适配到了Player
。
来看看结果:
整体来看我们的代码还是很简单,不过简单的代码已经将适配器模式讲解的很清楚了,那最后我们来思考一个问题,适配器模式体现了哪些面向对象的设计原则呢?针对接口编程有木有? 开闭原则有木有?
好了,适配器模式我们就说到这里,最后是文章的实例代码下载:http://download.csdn.net/detail/qibin0506/9420484