如何使用Golang实现适配器模式_兼容不兼容的接口

适配器模式在Go中通过组合和接口隐式实现,以桥接不兼容接口;例如用LegacyLoggerAdapter包装LegacyLogger并实现Logger接口,或用EmailWriter将sendEmail函数适配为Writer接口。

适配器模式的核心是让两个不兼容的接口能一起工作——Golang 没有继承,但通过组合和接口隐式实现,实现起来更轻量、更自然。

理解适配目标:定义“旧接口”与“新需求”

先明确谁需要被适配、谁是调用方。例如:

  • 已有类型 LegacyLogger 只有 LogError(msg string) 方法;
  • 但新业务代码依赖统一的 Logger 接口:Log(level string, msg string)

二者方法签名不匹配,无法直接传入。这时就需要一个适配器桥接。

用结构体组合 + 接口实现完成适配

Golang 中最常用的方式是定义一个新结构体,内嵌旧类型,并实现目标接口:

type LegacyLogger struct{}

func (l *LegacyLogger) LogError(msg string) { fmt.Println("[ERROR]", msg) }

// 目标接口 type Logger interface { Log(level string, msg string) }

// 适配器:包装 LegacyLogger,实现 Logger 接口 type LegacyLoggerAdapter struct { *LegacyLogger // 组合复用 }

func (a *LegacyLoggerAdapter) Log(level string, msg string) { if level == "error" { a.LogError(msg) // 转发到原有逻辑 } else { fmt.Printf("[%s] %s\n", strings.ToUpper(level), msg) } }

调用时只需传入 &LegacyLoggerAdapter{&LegacyLogger{}},即可满足 Logger 类型要求。

函数适配器:适合简单场景或第三方库

若旧能力是函数(如 func(string) error),而你需要它满足某个接口,可封装为闭包或适配函数:

type Writer interface {
    Write([]byte) (int, error)
}

// 第三方函数:func(string) error func sendEmail(content string) error { / ... / }

// 函数适配器:转成 Writer type EmailWriter struct { sendFunc func(string) error }

func (e *EmailWriter) Write(p []byte) (int, error) { err := e.sendFunc(string(p)) return len(p), err }

// 使用 writer := &EmailWriter{sendEmail} io.WriteString(writer, "Hello from adapter!")

避免常见陷阱

  • 不要暴露被适配类型的原始方法:适配器应只提供目标接口契约,避免调用方误用内部旧方法;
  • 适配器应无状态或轻量:它只是转发层,不建议在其中维护复杂逻辑或缓存;
  • 优先用组合而非重写:Golang 不支持多继承,组合天然契合适配器模式语义;
  • 接口越小越好:比如只定义 Log() 而非 Log()/Debug()/Info()/Error(),降低适配成本。

适配器不是万能胶,而是精准对接的桥梁——写清楚“谁适配谁”“怎么转译”,Golang 的接口机制会让它既清晰又可靠。