Go中桥接模式通过组合+接口依赖实现,抽象层持实现层接口引用,接口定义置于共享包避免循环依赖,SetRenderer支持运行时切换,性能开销主要在接口动态派发。
Go 没有传统 OOP 的 interface extends interface 或抽象类,所以“桥接”不是靠语法继承实现的,而是靠组合 + 接口依赖。核心是:让抽象层(如 Renderer)持有实现层(如 LinuxRenderer、WindowsRenderer)的接口引用,而非具体类型。
常见错误是试图用嵌入 struct 模拟继承,或把实现细节暴露给抽象层——这会破坏桥接的解耦目标。
RenderShape()),不关心 OS、图形库、线程模型type Renderer interface {
RenderCircle(x, y, r float64)
RenderRect(x, y, w, h float64)
}桥接结构天然涉及两个方向的依赖:抽象包需要引用实现接口,实现包又要实现该接口。若不加约束,容易出现 import cycle not allowed。
正确做法是把接口定义放在最上层共享包(如 shape/render),抽象逻辑(如 shape.Circle)和实现逻辑(如 render/opengl)各自独立 import 它,互不 import 对方。
shape/ 包 import render/opengl
render/opengl 包 import shape/
render.Renderer 接口,但不感知 shape 类型circle := &shape.Circle{X: 10, Y: 20, Radius: 5}
openglR := &opengl.Renderer{}
circle.SetRenderer(openglR) // 组合注入
circle.Draw() // 调用 openglR.RenderCircle(...)SetRenderer 比构造时传参更灵活?桥接的价值在于运行时动态切换实现。如果在 NewCircle(x, y, r, rder Renderer) 中硬编码 renderer,就失去了“桥”的可替换性。
SetRenderer 支持
Renderer 验证 draw 行为,无需启动图形上下文http.Server)也提供 SetXXX 方法Draw() 前应检查 r.renderer != nil,或在 SetRenderer 中 panic 提前报错Go 的接口调用有微小间接成本(需查 iface 表),但远小于网络 I/O 或内存分配。真正影响性能的是误用桥接导致的冗余抽象。
SVGRenderer 一种,还硬拆 Renderer 接口)Render()、Resize(),而非暴露 GetGLContext() 这类实现细节RenderCircle)可考虑用函数字段替代接口字段:type Circle struct { renderFunc func(x, y, r float64) },省去接口动态派发桥接是否必要,取决于你是否真要同时维护多套实现并允许它们独立演进。否则,一个干净的函数式封装可能更直接。