適配器模式
定義
適配器模式的英文翻譯是Adapter Design Pattern。顧名思義,這個模式就是用來做適配的,它將不兼容的接口轉換為可兼容的接口,讓原本由於接口不兼容而不能一起工作的類可以一起工作。
舉個栗子:
現在比較新款的電腦都有USB-C接口,但是我們目前的鼠標鍵盤的接口都是傳統的USB接口,所以是不能使用的,這時候我們會買個轉接口來進行接口的轉接,那么這個轉接口在設計模式中就是適配器。
代碼實現
// 基礎的播放功能
type MediaPlayer interface {
play(audioType string, fileName string)
}
// 不同的播放器平台
type AdvancedMediaPlayer interface {
playVlc(fileName string)
playMp4(fileName string)
}
// VlcPlayers
type VlcPlayers struct {
}
func (v *VlcPlayers) playVlc(fileName string) {
fmt.Println("正在播放" + fileName)
}
func (v *VlcPlayers) playMp4(fileName string) {
fmt.Println("格式不支持")
}
// Mp4Player
type Mp4Player struct {
}
func (m *Mp4Player) playVlc(fileName string) {
fmt.Println("格式不支持")
}
func (m *Mp4Player) playMp4(fileName string) {
fmt.Println("正在播放" + fileName)
}
// 適配器
type MediaAdapter struct {
MusicPlayer AdvancedMediaPlayer
}
func NewMediaAdapter(audioType string) *MediaAdapter {
var mediaAdapter MediaAdapter
switch audioType {
case "vlc":
mediaAdapter.MusicPlayer = &VlcPlayers{}
case "mp4":
mediaAdapter.MusicPlayer = &Mp4Player{}
default:
panic("不支持的類型")
}
return &mediaAdapter
}
func (m *MediaAdapter) play(audioType string, fileName string) {
switch audioType {
case "vlc":
m.MusicPlayer.playVlc(fileName)
case "mp4":
m.MusicPlayer.playMp4(fileName)
}
}
// AudioPlayer 音頻播放器類
type AudioPlayer struct {
mediaAdapter *MediaAdapter
}
// Play 播放音頻
func (auPlayer *AudioPlayer) Play(audioType, fileName string) {
if audioType == "mp3" {
fmt.Println("正在播放" + fileName)
return
}
auPlayer.mediaAdapter = NewMediaAdapter(audioType)
auPlayer.mediaAdapter.play(audioType, fileName)
}
測試文件
func TestPlayer(t *testing.T) {
ad := AudioPlayer{}
ad.Play("mp4", "荷塘月色")
ad.Play("vlc", "小蘋果")
ad.Play("mp3", "天空之城")
}
這里做個簡單的分析
1、我們有一個 AudioPlayer ,但是只能播放 mp3;
2、我們希望 AudioPlayer 也可以播放 mp3 和 vlc;
3、引入了一個 MediaAdapter ,通過適配器來處理不支持的功能,對於 AudioPlayer 來講,它只用需要調用 MediaAdapter 就能實現各種播放格式音頻的播放;
4、MediaAdapter 對各種格式進行了包裝,不同的格式音頻,可以有用相同的調用方法。
放一張結構圖

優點
1、可以讓任何兩個沒有關聯的類一起運行。
2、提高了類的復用。
3、增加了類的透明度。
4、靈活性好。
缺點
過多地使用適配器,會讓系統非常零亂,不易整體進行把握
一般來說,適配器模式可以看作一種“補償模式”,用來補救設計上的缺陷。應用這種模式算是“無奈之舉”,如果在設計初期,我們就能協調規避接口不兼容的問題,那這種模式就沒有應用的機會了。
如果大量的使用這種模式,可能就是我們的前期的設計有很大的問題,就需要考慮重構了
適用范圍
1、封裝有缺陷的接口設計
2、統一多個類的接口設計
3、替換依賴的外部系統
4、兼容老版本接口
5、適配不同格式的數據
代理、橋接、裝飾器、適配器4種設計模式的區別
代理模式:代理模式在不改變原始類接口的條件下,為原始類定義一個代理類,主要目的是控制訪問,而非加強功能,這是它跟裝飾器模式最大的不同。
橋接模式:橋接模式的目的是將接口部分和實現部分分離,從而讓它們可以較為容易、也相對獨立地加以改變。
裝飾器模式:裝飾者模式在不改變原始類接口的情況下,對原始類功能進行增強,並且支持多個裝飾器的嵌套使用。
適配器模式:適配器模式是一種事后的補救策略。適配器提供跟原始類不同的接口,而代理模式、裝飾器模式提供的都是跟原始類相同的接口。
參考
【文中代碼】https://github.com/boilingfrog/design-pattern-learning/tree/master/適配器模式
【大話設計模式】https://book.douban.com/subject/2334288/
【極客時間】https://time.geekbang.org/column/intro/100039001
【菜鳥教程】https://www.runoob.com/design-pattern/adapter-pattern.html
【詩適配器模式】https://boilingfrog.github.io/2021/11/14/使用go實現適配器模式/