适配器模式在go中通过组合和接口嵌入实现,核心是让不兼容类型满足统一接口;定义目标接口Notifier和已有类型EmailSender/SMSSender,再创建EmailAdapter/SMSAdapter结构体桥接行为,最后统一调用alert函数。

适配器模式的核心是让不兼容的接口能一起工作——golang 没有继承,但通过组合和接口嵌入,实现起来更轻量、更清晰。
定义目标接口与已有类型
先明确你希望统一对外暴露的接口(Target),再确认已有类型(Adaptee)的行为。比如:
- 目标接口:Notifier 要求有 Send(message String) 方法;
- 已有类型:EmailSender 有 SendEmail(to, body string),SMSSender 有 SendSMS(phone, text string) —— 它们无法直接满足 Notifier。
编写适配器结构体,组合并桥接行为
适配器不是改造原有类型,而是新建一个结构体,内嵌或持有 Adaptee,并实现 Target 接口:
type EmailAdapter struct { emailSender *EmailSender } func (e *EmailAdapter) Send(message string) { e.emailSender.SendEmail("admin@example.com", message) } type SMSAdapter struct { smsSender *SMSSender } func (s *SMSAdapter) Send(message string) { s.smsSender.SendSMS("13800138000", message) }
注意:适配器只负责“翻译”调用,不改变原逻辑。参数映射、默认值填充、错误转换等都在这里处理。
立即学习“go语言免费学习笔记(深入)”;
统一使用,隐藏底层差异
现在你可以把不同适配器当成同一类型传入业务逻辑:
func Alert(n Notifier, msg string) { n.Send(msg) // 不关心背后是邮件还是短信 } Alert(&EmailAdapter{&EmailSender{}}, "服务器宕机!") Alert(&SMSAdapter{&SMSSender{}}, "服务器宕机!")
新增渠道(如 Dingtalk、Webhook)只需写新适配器,不修改 Alert 或其他依赖 Notifier 的代码。
进阶:用函数适配器简化简单场景
如果 Adaptee 是简单函数,可直接用闭包构造适配器,避免定义结构体:
func NewHTTPNotifier(client *http.Client, url string) Notifier { return Notifier(func(msg string) { http.Post(url, "text/plain", strings.NewReader(msg)) }) }
这种函数式适配器适合轻量集成,代码更紧凑,也符合 Go 的务实风格。
基本上就这些。Go 的适配器不靠继承靠组合,不靠抽象类靠接口,写起来干净,维护时也容易替换——关键在于分清谁是契约(接口)、谁是实现(具体类型)、谁是胶水(适配器)。