适配器模式在Go重构中完全适用,是副作用最小的渐进式迁移手段;它通过新增结构体+接口隐式实现完成翻译,不修改旧代码,仅作胶水层包装;需避免暴露旧方法、嵌入业务逻辑或忽略错误转换。

适配器模式在Go重构中是否适用?
完全适用,而且是Go重构旧代码时最自然、副作用最小的手段之一。它不修改原有类型,不破坏已有调用链,只通过新增结构体+接口实现完成“翻译”,特别适合渐进式迁移。
为什么不用改旧代码就能接入新接口?
因为Go的接口是隐式实现的——只要新结构体实现了目标接口的所有方法,它就自动满足该接口,无需改动旧类型的定义或声明。适配器只是个“胶水层”,把旧方法调用包装成新接口签名。
- 旧类型
LegacyLogger只有LogMessage(msg string) - 新业务依赖
ModernLogger接口:要求Info(msg string)和Error(msg string) - 适配器
LoggerAdapter内嵌*LegacyLogger,并在Info中调用a.legacy.LogMessage("[INFO] " + msg)—— 逻辑没动,只是加了前缀和路由
重构时最容易踩的三个坑
不是写不出适配器,而是写得“太重”或“太松”,导致后续维护困难。
-
暴露内部旧方法:比如让
LoggerAdapter直接导出LogMessage方法,调用方可能绕过适配逻辑直接用,破坏统一契约 -
在适配器里做业务判断:例如在
Pay(amount float64)适配器里加风控校验、日志埋点——这些该放在上层服务,不是适配器的职责 -
忽略错误转换:第三方函数返回
string或bool,但目标接口要求error,必须显式包装(如errors.New(result)),否则 panic 或静默失败
什么时候该用函数适配器而不是结构体?
当被适配的是简单函数(比如 func(string) error),且不需要状态或多次复用时,闭包比定义结构体更轻量、更直观。
立即学习“go语言免费学习笔记(深入)”;
type Writer interface {
Write([]byte) (int, error)
}
func NewHTTPWriter(client *http.Client, url string) Writer {
return Writer(func(p []byte) (int, error) {
_, err := client.Post(url, "text/plain", bytes.NewReader(p))
return len(p), err
})
}
这种写法避免了额外的 struct 定义和字段管理,但不可用于需要保存状态(如重试次数、认证 token)的场景。
适配器本身不解决设计腐化,它只是让腐化部分“可隔离”。真正要警惕的是:当一个适配器开始频繁添加 if/else 分支、缓存字段或回调注册时,说明它已经超出了“接口翻译”的边界——该停下来重新审视抽象是否合理了。










