介绍
适配器模式(Adapter Pattern)是作为两个不兼容接口之间的桥梁。适配器模式将一个类的接口转换为另一个类的接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。
主要涉及的角色有:
- 目标接口(Target Interface):客户端期望的接口,适配器将原始接口转换成目标接口。
- 适配器(Adapter):适配器类实现了目标接口,并包含对原始类的引用。它将客户端的请求转发给原始类,并根据需要进行适配转换。
- 原始类(Adaptee):原始类是需要被适配的类,它拥有不符合目标接口的方法。
优点
- 适配器模式可以将客户端和原始类解耦,客户端可以通过适配器调用原始类的方法,而无需直接与原始类交互。
- 通过适配器,可以复用已有的类,而无需修改其代码。
- 可以通过添加新的适配器类来适配更多的类,而无需修改现有的代码。
缺点
- 配器模式引入了适配器类,增加了额外的类和代码,可能会增加系统的复杂性。
- 适配器模式在每次请求转发时都需要进行适配转换,可能会导致运行时性能略有损失。
使用场景
- 将旧的接口适配到新的系统中:当需要在现有系统中使用某个已有的类,但其接口与系统要求的接口不一致时,可以使用适配器模式进行适配。
- 与第三方库或接口的集成:当需要使用第三方库或接口,但其接口与系统的接口不兼容时,可以通过适配器模式将其转换为系统所需的接口。
- 对已有的类进行功能扩展:通过适配器模式,可以为已有的类添加额外的功能,而无需修改原有的类。
代码示例
正常实现
package main
import "fmt"
// 定义Logger接口
type Logger interface {
Log(msg string)
}
type LoggerImpl struct{}
func (l *LoggerImpl) Log(msg string) {
fmt.Println("logger log:", msg)
}
// 定义第三方Logger接口
type ThirdPartyLogger interface {
LogMessage(msg string)
}
type ThirdLoggerImpl struct{}
func (t *ThirdLoggerImpl) LogMessage(msg string) {
fmt.Println("third logger log:", msg)
}
// 定义适配器
type LoggerAdapter struct {
ThirdLoggerImpl *ThirdLoggerImpl
}
func (a *LoggerAdapter) Log(msg string) {
a.ThirdLoggerImpl.LogMessage(msg)
}
func main() {
logger := &LoggerImpl{}
logger.Log("原接口")
// 创建第三方日志记录器对象
thirdLogger := &ThirdLoggerImpl{}
// 创建适配器对象,将第三方日志记录器适配成Logger接口
adapter := &LoggerAdapter{
ThirdLoggerImpl: thirdLogger,
}
// 使用适配后的接口打印日志
adapter.Log("第三方接口适配原接口")
}
上面的代码中,第三方ThirdPartyLogger
接口和原Logger
接口不兼容。通过LoggerAdapter
的适配器类,它实现了Logger
接口,适配器类内部包含一个ThirdLoggerImpl
对象,并将其方法适配成符合Logger
接口的形式。
接口嵌套
package main
import "fmt"
type OldInterface interface {
GetData() string
}
type OldImpl struct {
data string
}
func (o *OldImpl) GetData() string {
return o.data
}
type NewInterface interface {
NewMethod() string
}
type Adapter struct {
OldInterface
}
func (a *Adapter) NewMethod() string {
data := a.GetData() // 通过接口方法获取字段值
return "New method: " + data
}
func main() {
oldObj := &OldImpl{
data: "Hello, World!",
}
adapter := &Adapter{
OldInterface: oldObj,
}
result := adapter.NewMethod()
fmt.Println(result) // New method: Hello, World!
}
适配器通过接口嵌套的方式来实现新接口,并在新接口的方法中调用旧接口的方法。但不能直接访问接口的字段。如果接口定义了字段,适配器可以通过其他方式来访问这些字段,例如通过接口方法的参数或返回值。
上面代码中创建了一个OldImpl
的实例,并将其赋值给Adapter
结构体的OldInterface
字段。然后通过适配器的NewMethod()
方法,再调用a.GetData()
方法,就可以访问OldInterface
接口中字段data
的值。