Go解耦本质是隐式实现接口:结构体只要实现接口方法签名即自动满足,调用方只依赖接口契约;应传接口而非具体类型,通过依赖注入将创建权交出,避免硬编码实现。
Go 的解耦本质来自「隐式实现」:只要结构体实现了接口定义的全部方法签名(名称、参数、返回值),就自动满足该接口,无需 implements 或 extends 声明。这使得调用方完全不感知底层类型是谁——它只依赖接口契约。
*MyStruct 而不是 MyInterface,导致后续替换实现时必须改所有调用点Logger 而非 *FileLogger
MockLogger 时,业务代码一行都不用动解耦的关键动作是「把创建权交出去」。如果一个服务内部直接 new DBClient(),那它就跟数据库实现绑死了;改成接收 DBClientInterface 参数,创建逻辑就上移到调用方或工厂中。
userRepo UserRepository 而非自己初始化 &MySQLUserRepo{}
&InMemoryUserRepo{},零依赖、秒级运行ExecRawSQL),反而把实现细节泄漏出去,破坏抽象看 io.Copy 函数签名:func Copy(dst Writer, src Reader) (written int64, err error)。它不关心 dst 是文件、网络连接还是 bytes.Buffer,只要实现了 Write([]byte) (int, error) 就行。
Write,就能无缝接入 io.Copy 流程*os.File,那你就没法用 gzip.Writer 或 http.Response.Body 替代interface{} 能接任何类型,但它不提供任何行为约束,无法实现真正的解耦——你拿到它之后还得用类型断言或反射才能干活,反而增加脆弱性。
fmt.Stringer 替代 interface{} 来统一字符串输出逻辑,调用方就知道一定能调 String()
interface{} 往往是接口设计没想清楚的表现,后期很难加校验和 mockLog(string) 开始,而不是一上来就设计带上下文、
字段、级别、采样的大接口。