Go中桥接模式用组合+接口替代继承,核心是将抽象与实现分离为独立接口层级,运行时动态组合;典型应用如Logger组合Formatter和Writer,支持正交扩展。

桥接模式在 Go 中不靠抽象类和继承实现,而是用组合 + 接口,核心是把“抽象”和“实现”分离到两个独立的接口层级,运行时动态组合。
为什么 Go 不适合传统桥接模式写法
Go 没有抽象类、不能继承方法、也不支持多继承,强行模仿 UML 类图里的 Abstraction ←→ Implementor 继承链,只会让代码变重、接口膨胀、空接口泛滥。
- 常见错误:定义
type Abstraction interface { Operation() }和type Implementor interface { Do() },再让具体结构体同时实现两者——这根本没解耦,只是把两件事塞进一个类型 - 真正有效的桥接,是让高层逻辑只依赖一个接口,而该接口的实现内部又持有另一个接口的实例
- 关键判断标准:能否在不改调用方代码的前提下,替换底层行为的具体实现?
用组合实现可替换的渲染器(典型桥接场景)
比如日志输出既要支持不同格式(JSON / Plain),又要支持不同目标(Stdout / File / Network)。格式和目标应正交变化——这正是桥接要解决的问题。
type Logger interface {
Log(msg string)
}
type Formatter interface {
Format(level, msg string) string
}
type Writer interface {
Write(data string) error
}
// Bridge: Logger 的实现组合了 Formatter 和 Writer
type ConsoleLogger struct {
formatter Formatter
writer Writer
}
func (l *ConsoleLogger) Log(msg string) {
formatted := l.formatter.Format("INFO", msg)
l.writer.Write(formatted)
}
-
ConsoleLogger不绑定任何具体格式或输出方式,它只依赖两个接口 - 你可以传入
&JSONFormatter{}+&FileWriter{path: "app.log"},也可以换为&PlainFormatter{}+&NetworkWriter{addr: "127.0.0.1:9000"} - 新增一种格式?只需实现
Formatter;新增一种输出?只需实现Writer;都不用动ConsoleLogger
避免过度设计:什么时候不该用桥接
桥接不是万能解耦工具。如果只有 1–2 种组合、且未来几乎不会扩展,硬套桥接反而增加间接层和理解成本。
立即学习“go语言免费学习笔记(深入)”;
- 错误信号:
Formatter接口只有一个实现,Writer接口也只有一个实现,但你还是写了 4 层结构体嵌套 - 更轻量替代:直接用函数字段,例如
type Logger struct { Format func(string) string; Output func(string) error } - 性能敏感路径:接口调用有微小开销,高频日志场景下,函数字段或泛型(Go 1.18+)可能更合适
- 配置驱动场景:若所有组合都由 YAML 控制,建议用工厂函数统一创建,而不是暴露一堆组合构造逻辑给调用方
桥接模式真正的价值不在“看起来像设计模式”,而在于你能否在新增一个维度变化时,不触碰已有模块的代码。Go 里最自然的体现,就是让一个结构体持有一组接口字段,并在初始化时注入具体实现——其余全是围绕这个组合关系做减法,不是加法。










