适配器模式设计意图
将一个类型的接口转换成客户希望的另外一个接口,使原本由于接口不兼容而不能一起工作的类可以一起工作。
适用性
.想适用一个已经存在的类型,而其接口不符合需求
.创建一个可以复用的类型,该类型可以与其他不相关的类型或不可预见的类型协同工作。
.(仅适用于对象Adapter)想使用一些已经存在的子类,但是不可能对每个子类修改为匹配他们的接口,对象适配器可以适配它的父类接口。
结构(uml)
适配器模式的类型
适配器可以分为类型适配器和对象适配器。
对于类型适配器:
.用一个具体的adapter类对adaptee和target进行匹配。结果是当我们想要匹配一个类及它的所有子类时,类adapter将无法胜任工作。
.类适配器可以使adapter重定义adptee的部分行为,因为adapter是adaptee的子类
.仅仅引入一个对象,并不需要额外的指针间接得到adaptee
对应对象适配器:
.对象适配器允许一个adapter和多个adaptee,即多个adaptee及其子类一起工作。
.对象适配器可能在重用方面会比较差,因为可以使用到的是adaptee的子类而不是adaptee本身。
总之,使用适配器,最重要的考虑因素为两个接口的相似程度,没有理由去适配两个毫无关联的接口。
golang实现
package main
import (
"fmt"
)
type OldInterface interface {
InsertToDatabase(Data interface{}) (bool, error)
}
type AddCustomInfoToMysql struct {
DbName string
}
func (pA *AddCustomInfoToMysql) InsertToDatabase(info interface{}) (bool, error) {
switch info.(type) {
case string:
fmt.Println("add ", info.(string), " to ", pA.DbName, " successful!")
}
return true, nil
}
type NewInterface interface {
SaveData(Data interface{}) (bool, error)
}
type Adapter struct {
OldInterface
}
func (pA *Adapter) SaveData(Data interface{}) (bool, error) {
fmt.Println("In Adapter")
return pA.InsertToDatabase(Data)
}
func main() {
var iNew NewInterface
iNew = &Adapter{OldInterface: &AddCustomInfoToMysql{DbName: "mysql"}}
iNew.SaveData("helloworld")
return
}
从实现例子可以看出,老接口方法为InsertToDatabase,新接口方法为SaveData。两者具有一点的相似性。当系统不想保留接口的时候,就可以用适配器来修饰。