Skip to content

简介

将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

适配器模式中的角色和职责

Target(目标抽象类)

目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。

Adapter(适配器类)

适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。

Adaptee(适配者类)

适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。 根据对象适配器模式结构图,在对象适配器中,客户端需要调用request()方法,而适配者类Adaptee没有该方法,但是它所提供的specificRequest()方法却是客户端所需要的。为了使客户端能够使用适配者类,需要提供一个包装类Adapter,即适配器类。这个包装类包装了一个适配者的实例,从而将客户端与适配者衔接起来,在适配器的request()方法中调用适配者的specificRequest()方法。因为适配器类与适配者类是关联关系(也可称之为委派关系),所以这种适配器模式称为对象适配器模式

代码

在此的例子是手机5V

package main

import "fmt"

//适配的目标
type V5 interface {
    Use5V()
}

//业务类,依赖V5接口
type Phone struct {
    v V5
}

func NewPhone(v V5) *Phone {
    return &Phone{v}
}

func (p *Phone) Charge() {
    fmt.Println("Phone进行充电...")
    p.v.Use5V()
}


//被适配的角色,适配者
type V220 struct {}

func (v *V220) Use220V() {
    fmt.Println("使用220V的电压")
}

//电源适配器
type Adapter struct {
    v220 *V220
}

func (a *Adapter) Use5V() {
    fmt.Println("使用适配器进行充电")

    //调用适配者的方法
    a.v220.Use220V()
}

func NewAdapter(v220 *V220) *Adapter {
    return &Adapter{v220}
}



// ------- 业务逻辑层 -------
func main() {
    iphone := NewPhone(NewAdapter(new(V220)))

    iphone.Charge()
}

总结

优点

  1. 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构。
  2. 增加了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用。
  3. 灵活性和扩展性都非常好,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”

缺点

  1. 适配器中置换适配者类的某些方法比较麻烦。

适用场景

  1. 系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系统的需要,甚至没有这些类的源代码。
  2. 想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。