Skip to content

设计模式之适配器模式

853字约3分钟

设计模式适配器模式

2024-10-23

定义

适配器模式(Adapter) 是最常用的结构型模式之一,在现实生活中,适配器模式也是处处可见,比如电源插头转换器,它可以让英式的插头工作在中式的插座上。 简单来说,就是 适配器模式让原本因为接口不匹配而无法一起工作的两个类/结构体能够一起工作

适配器模式所做的就是将一个接口 Adaptee,通过适配器 Adapter 转换成 Client 所期望的另一个接口 Target 来使用,实现原理也很简单,就是 Adapter 通过实现 Target 接口,并在对应的方法中调用 Adaptee 的接口实现。

适配器模式示意图

典型场景

  • 将一个接口 A 转换成用户希望的另外一个接口 B,这样就能使原来不兼容的接口 A 和接口 B 相互协作。
  • 老系统的重构 。在不改变原有接口的情况下,让老接口适配到新的接口。

优缺点

优点

能够使 Adaptee 和 Target 之间解耦。通过引入新的 Adapter 来适配 Target,Adaptee 无须修改,符合开闭原则灵活性好 ,能够很方便地通过不同的适配器来适配不同的接口。

缺点

增加代码复杂度。适配器模式需要新增适配器,如果滥用会导致系统的代码复杂度增大。

开闭原则

开闭原则(The Open-Close Principle,OCP)中,“开”指的是 对扩展开放 ,“闭”指的是 对修改封闭

通俗地讲就是,一个软件系统应该 具备良好的可扩展性 ,新增功能应当 通过扩展 的方式实现,而不是在已有的代码基础上修改。

示例

以常见的日志操作为例

假设我们有一个现成的 Logger 接口:

type Logger interface {
    Log(message string)
}

我们还有一个现成的 ThirdPartyLogger ,它有一个不同的接口:

type ThirdPartyLogger interface {
    LogMessage(msg string)
}

我们想要使用 ThirdPartyLogger 来实现 Logger 接口,可以使用适配器模式来完成。

我们首先 定义一个适配器类型 ThirdPartyLoggerAdapter,该类型包装了 ThirdPartyLogger,并实现了 Logger 接口:

type ThirdPartyLoggerAdapter struct {
    logger ThirdPartyLogger
}

func (a *ThirdPartyLoggerAdapter) Log(message string) {
    a.logger.LogMessage(message)
}

在上面的代码中,ThirdPartyLoggerAdapter 包装了 ThirdPartyLogger 实例,并实现了 Log 方法,该方法将接收到的消息转发给被包装的 ThirdPartyLogger 实例的 LogMessage 方法。

现在,我们可以使用 ThirdPartyLoggerAdapter 来适配 ThirdPartyLogger 到 Logger 接口:

func main() {
    // 创建一个 ThirdPartyLogger 实例
    thirdPartyLogger := &MyThirdPartyLogger{}

    // 使用适配器创建一个 Logger 实例
    logger := &ThirdPartyLoggerAdapter{logger: thirdPartyLogger}

    // 使用 Logger 实例记录消息
    logger.Log("这是一条消息")
}

在上面的代码中,我们创建了一个 ThirdPartyLogger 实例,并将其包装在 ThirdPartyLoggerAdapter 中,以便将其转换为 Logger 接口。然后,我们使用 Logger 实例来记录消息。

总结

适配器模式可以帮助我们将现有的类与其他类协同工作,从而使得代码更加简洁和易于维护。 在 Go 语言中,适配器模式通常使用接口来实现,通过定义一个适配器类型来包装被适配者类型并实现目标接口。