结构型模式-适配器模式

什么是适配器模式

适配器是一种结构型设计模式, 它能使接口不兼容的对象能够  相互合作

  1. 客户端(Client)是包含当前程序业务逻辑的类
  2. 客户端接口(Client Interface)描述了其他类与客户端代码 合作时必须遵循的协议
  3. 服务(Service)中有一些功能类(通常来自第三方或遗留系 统)。客户端与其接口不兼容,因此无法直接调用其功能
  4. 适配器(Adapter)是一个可以同时与客户端和服务交互的 类:它在实现客户端接口的同时封装了服务对象。适配器接 受客户端通过适配器接口发起的调用,并将其转换为适用于 被封装服务对象的调用。

Example

客户端

package main

import "fmt"

type Client struct {
}

func (c *Client) InsertLightningConnectorIntoComputer(com Computer) {
fmt.Println("Client inserts Lightning connector into computer.")
com.InsertIntoLightningPort()
}

客户端接口

package main

type Computer interface {
InsertIntoLightningPort()
}

服务

package main

import "fmt"

type Mac struct {
}

func (m *Mac) InsertIntoLightningPort() {
fmt.Println("Lightning connector is plugged into mac machine.")
}

未知服务a

package main

import "fmt"

type Windows struct{}

func (w *Windows) insertIntoUSBPort() {
fmt.Println("USB connector is plugged into windows machine.")
}

未知服务a适配器

package main

import "fmt"

type WindowsAdapter struct {
windowMachine *Windows
}

func (w *WindowsAdapter) InsertIntoLightningPort() {
fmt.Println("Adapter converts Lightning signal to USB.")
w.windowMachine.insertIntoUSBPort()
}

main

package main

func main() {

client := &Client{}
mac := &Mac{}

client.InsertLightningConnectorIntoComputer(mac)

windowsMachine := &Windows{}
windowsMachineAdapter := &WindowsAdapter{
windowMachine: windowsMachine,
}

client.InsertLightningConnectorIntoComputer(windowsMachineAdapter)
}

适用场景

  1. 当你希望使用某个类,但是其接口与其他代码不兼容时,可 以使用适配器类。
  • 适配器模式允许你创建一个中间层类,其可作为代码与遗留 类、第三方类或提供怪异接口的类之间的转换器。
  1. 如果您需要复用这样一些类,他们处于同一个继承体系,并 且他们又有了额外的一些共同的方法,但是这些共同的方法 不是所有在这一继承体系中的子类所具有的共性
  • 你可以扩展每个子类,将缺少的功能添加到新的子类中。但 是,你必须在所有新子类中重复添加这些代码,这样会使得 代码有坏味道

优缺点

优点

  • _单一职责原则_你可以将接口或数据转换代码从程序主要业 务逻辑中分离
  • 开闭原则。只要客户端代码通过客户端接口与适配器进行交 互,你就能在不修改现有客户端代码的情况下在程序中添加 新类型的适配器

缺点

  • 代码整体复杂度增加,因为你需要新增一系列接口和类。有 时直接更改服务类使其与其他代码兼容会更简单

与其他模式的关系

  • 桥接通常会于开发前期进行设计,使你能够将程序的各个部 分独立开来以便开发。另一方面,适配器通常在已有程序中 使用,让相互不兼容的类能很好地合作
  • 适配器可以对已有对象的接口进行修改,装饰则能在不改变 对象接口的前提下强化对象功能。此外,装饰还支持递归组 合,适配器则无法实现
  • 适配器能为被封装对象提供不同的接口,代理能为对象提供 相同的接口,装饰则能为对象提供加强的接口
  • 外观为现有对象定义了一个新接口,适配器则会试图运用已 有的接口。适配器通常只封装一个对象,外观通常会作用于 整个对象子系统上
  • 桥接、状态和策略(在某种程度上包括适配器)模式的接口 非常相似。实际上,它们都基于组合模式——即将工作委派 给其他对象,不过也各自解决了不同的问题。模式并不只是 以特定方式组织代码的配方,你还可以使用它们来和其他开 发者讨论模式所解决的问题