适配器模式是一种设计模式,用来解决接口不兼容的问题。它的作用是让原本因为接口不兼容而无法一起工作的类能够协同工作。通俗地说,它就像是一种“转换器”,能够把一种接口转化为另一种接口,从而让不同的系统或组件可以一起使用。
通俗解释
想象一下你在国外旅行,发现你的手机充电器只能插在中国的插座上(两脚扁插头),但你现在在欧洲,而欧洲的插座是圆孔的。这个时候,你需要一个电源适配器,把你的充电器插头转换成能插进欧洲插座的形状,这样你才能给手机充电。适配器就是那个中间转换的工具。
在编程中,适配器模式的作用就类似于这种电源适配器。当两个类的接口不兼容时,适配器模式通过引入一个中间类(适配器),让这两个类能够一起工作。
适配器模式解决的问题
适配器模式主要解决的是“如何让两个不兼容的类或者接口能够协同工作”。通常,这两个类之间存在一定的关联性,但由于接口不同,不能直接一起使用。适配器模式通过将一个类的接口转化为客户端期望的接口,让不兼容的类能够在一起使用而无需修改它们的原始代码。
使用场景
• 集成遗留系统:当你需要将新系统集成到旧系统中,但新旧系统的接口不兼容时,可以使用适配器模式。
• 第三方库兼容:当你想要使用一个第三方库,但它的接口与你的系统接口不兼容时,适配器可以帮助你桥接这两个接口。
• 接口标准化:在开发中,当你需要统一不同的接口形式时,可以通过适配器模式将各种不同的接口转换为统一的形式。
下面是一个使用适配器模式的 Go 语言代码示例,通过电源适配器的比喻来展示如何在编程中使用适配器模式,将不兼容的接口连接起来。
示例场景
假设我们有一个中国的插头(两脚扁插头)和一个欧洲的插座(圆孔插座)。我们的中国插头(ChinaPlug
)只能插在中国的插座上(ChinaSocket
),而我们的欧洲插座(EuroSocket
)只能接受圆孔的插头。我们需要通过一个适配器(PlugAdapter
)将中国插头适配到欧洲插座上。
1. 定义中国插头和插座接口
package main
import "fmt"
// ChinaPlug 是中国插头的接口
type ChinaPlug interface {
InsertChinaPlug() string
}
// ChinaSocket 是中国插座的接口
type ChinaSocket interface {
PlugIn(plug ChinaPlug) string
}
2. 实现中国插头和插座
// ChinesePlug 是一个实现了 ChinaPlug 接口的具体类
type ChinesePlug struct{}
func (p *ChinesePlug) InsertChinaPlug() string {
return "中国插头插入中国插座"
}
// ChineseSocket 是一个实现了 ChinaSocket 接口的具体类
type ChineseSocket struct{}
func (s *ChineseSocket) PlugIn(plug ChinaPlug) string {
return plug.InsertChinaPlug()
}
3. 定义欧洲插座接口
// EuroSocket 是欧洲插座的接口
type EuroSocket interface {
PlugInEuroSocket() string
}
4. 实现欧洲插座
// EuropeanSocket 是一个实现了 EuroSocket 接口的具体类
type EuropeanSocket struct{}
func (s *EuropeanSocket) PlugInEuroSocket() string {
return "欧洲插座准备接收插头"
}
5. 创建适配器 PlugAdapter
,适配中国插头到欧洲插座
// PlugAdapter 是适配器类,适配中国插头到欧洲插座
type PlugAdapter struct {
chinesePlug ChinaPlug
}
func (a *PlugAdapter) PlugInEuroSocket() string {
return a.chinesePlug.InsertChinaPlug() + " 通过适配器接入欧洲插座"
}
6. 使用适配器将中国插头插入欧洲插座
func main() {
// 创建一个中国插头
chinaPlug := &ChinesePlug{}
// 创建一个欧洲插座
euroSocket := &EuropeanSocket{}
// 使用适配器将中国插头适配到欧洲插座
adapter := &PlugAdapter{chinesePlug: chinaPlug}
// 插入欧洲插座
fmt.Println(euroSocket.PlugInEuroSocket())
fmt.Println(adapter.PlugInEuroSocket())
}
7. 运行结果
当你运行这段代码时,输出将会是:
欧洲插座准备接收插头
中国插头插入中国插座 通过适配器接入欧洲插座
代码解析
- ChinaPlug 和 ChinaSocket:定义了中国插头和插座的接口和实现。
- EuroSocket:定义了欧洲插座的接口和实现。
- PlugAdapter:适配器类,实现了
EuroSocket
接口,并在内部持有一个ChinaPlug
对象。在PlugInEuroSocket
方法中,它调用了ChinaPlug
的InsertChinaPlug
方法,同时通过适配器将其适配到欧洲插座的接口。 - main 函数:演示了如何使用适配器模式将中国插头适配到欧洲插座上。
这个示例展示了适配器模式的实际应用场景,通过引入适配器类,成功让不兼容的接口协同工作。
package adapter
import "fmt"
// ApplePlug 苹果手机充电插槽
type ApplePlug interface {
ConnectLightning() string
}
// IPhone 苹果系列手机
type IPhone struct {
model string
}
// NewIPhone 苹果手机创建方法
func NewIPhone(model string) *IPhone {
return &IPhone{
model: model,
}
}
// ConnectLightning 苹果手机Lightning充电插槽
func (i *IPhone) ConnectLightning() string {
return fmt.Sprintf("%v connect lightning plug", i.model)
}
// CommonPlug 通用的USB电源插槽
type CommonPlug interface {
ConnectUSB() string
}
// ApplePhonePlugAdapter 苹果Lightning充电插槽适配通用USB充电插槽
type ApplePhonePlugAdapter struct {
iPhone ApplePlug
}
// NewApplePhonePlugAdapter 创建苹果手机适配USB充电插槽适配器
func NewApplePhonePlugAdapter(iPhone ApplePlug) *ApplePhonePlugAdapter {
return &ApplePhonePlugAdapter{
iPhone: iPhone,
}
}
// ConnectUSB 链接USB
func (a *ApplePhonePlugAdapter) ConnectUSB() string {
return fmt.Sprintf("%v adapt to usb ", a.iPhone.ConnectLightning())
}
// PowerBank 充电宝
type PowerBank struct {
brand string
}
// Charge 支持通用USB接口充电
func (p *PowerBank) Charge(plug CommonPlug) string {
return fmt.Sprintf("%v power bank connect usb plug, start charge for %v", p.brand, plug.ConnectUSB())
}
代码解析
1. ApplePlug 接口:定义了苹果手机的 Lightning 插槽。
2. IPhone 类:实现了 ApplePlug 接口,代表苹果手机。
3. CommonPlug 接口:定义了充电宝支持的通用 USB 接口。
4. ApplePhonePlugAdapter 类:适配器类,将苹果手机的 Lightning 插槽适配为充电宝的通用 USB 插槽。
5. PowerBank 类:代表充电宝,支持通用 USB 接口的充电。
6. TestAdapter 测试函数:展示了如何通过适配器将苹果手机连接到充电宝。
这个例子展示了如何使用适配器模式解决不同接口设备之间的兼容性问题,让旧接口设备也能与新接口设备一起工作。