适配器模式(Adapter)/包装器模式(Wrapper)
1.意图
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
2.适用性
以下情况使用Adapter模式
- 你想使用一个已经存在的类,而它的接口不符合你的需求。
- 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
- (仅适用于对象Adapter)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
3.结构
类适配器使用多重继承对一个接口与另一个接口进行匹配,如下图所示。
对象匹配器依赖于对象组合,如下图所示。
4.代码
package adapter
import (
"fmt"
"testing"
)
/*
# 适配器模式
在计算机编程中,适配器模式(有时候也称包装样式或者包装)
将一个类的接口适配成用户所期待的。一个适配允许通常因为
接口不兼容而不能在一起工作的类工作在一起,做法是将类自
己的接口包裹在一个已存在的类中。
适配器模式用于转换一种接口适配另一种接口。
实际使用中Adaptee一般为接口,并且使用工厂函数生成实例。
在Adapter中匿名组合Adaptee接口,所以Adapter类也拥有
SpecificRequest实例方法,又因为Go语言中非入侵式接口特征,
其实Adapter也适配Adaptee接口。
*/
type Phone struct {
name string
}
type MicroUsb interface {
LinkPhone(phone Phone)
}
type microUSBImpl struct {}
func NewMicroUSB()MicroUsb{
return µUSBImpl{}
}
func (this *microUSBImpl)LinkPhone(phone Phone){
fmt.Println("使用MicroUSB连接",phone.name)
}
type USB interface {
LinkUSBDevice()
}
type usbImpl struct {}
func (*usbImpl)LinkUSBDevice() {
fmt.Println("USB设备就绪......")
}
func NewUSB()USB{
return &usbImpl{}
}
//现在USB设备不能直接连接手机,怎么办?
//弄出一个OTG转接线,这个线就是一个 适配器
type OTG struct {
USB
}
func (this *OTG) LinkPhone(phone Phone) {
this.USB.LinkUSBDevice()
fmt.Println("使用OTG转接......带有MicroUSB接口的线")
NewMicroUSB().LinkPhone(phone)
}
//创建适配器
func NewOTG(usb USB)MicroUsb{
return &OTG{
USB:usb,
}
}
func TestAdapter(t *testing.T) {
usb:=NewUSB()
musb:=NewOTG(usb)
phone:=Phone{"大哥大"}
musb.LinkPhone(phone)
}
/*
=== RUN TestAdapter
USB设备就绪......
使用OTG转接......带有MicroUSB接口的线
使用MicroUSB连接 大哥大
--- PASS: TestAdapter (0.00s)
PASS
*/
// 我们的接口(新接口)——音乐播放
type MusicPlayer interface {
play(fileType string, fileName string)
}
// 在网上找的已实现好的库 音乐播放
// ( 旧接口)
type ExistPlayer struct {
}
func (*ExistPlayer) playMp3(fileName string) {
fmt.Println("play mp3 :", fileName)
}
func (*ExistPlayer) playWma(fileName string) {
fmt.Println("play wma :", fileName)
}
// 适配器
type PlayerAdaptor struct {
// 持有一个旧接口
existPlayer ExistPlayer
}
// 实现新接口
func (player *PlayerAdaptor) play(fileType string, fileName string) {
switch fileType {
case "mp3":
player.existPlayer.playMp3(fileName)
case "wma":
player.existPlayer.playWma(fileName)
default:
fmt.Println("暂时不支持此类型文件播放")
}
}
func TestPlayer( t *testing.T) {
player := PlayerAdaptor{}
player.play("mp3", "死了都要爱")
player.play("wma", "滴滴")
player.play("mp4", "复仇者联盟")
}