go 依赖注入实现的不少,主要的有:
wire 的实现是代码生成的方式,每次修改都要重新 go generate,不太方便,还是运行时反射方便一些。
uber 的 dig 和 facebook 的 inject 是基于运行时反射的实现,使用方式上有些区别,但这两个用起来都不太直观。
我心中“理想”的样子:
Foo {
A int `export:"x"` // 声明导出 x
}
func (Foo) SetUp() { Foo.A = 1 } // 这里手动设置 A,在 SetUp 返回后自动导出 x=Foo.A
Bar {
B int `export:"y"` // 声明导出 b
}
func (Bar) SetUp() { Bar.B = 2 } // 这里手动设置 B,在 SetUp 返回后自动导出 y=Bar.B
Baz {
A int `import:"x"` // 声明导入 x
B int `import:"y"` // 声明导入 y
C int `export:"z"` // 声明导出 z
}
func (Baz) SetUp() { Baz.C = Baz.A + Baz.B } // SetUp 被调用时,保证 x 、y 的值已被自动导入,即 Baz.A=x Baz.B=y 。接着是手动计算 C 的值( z=x+y ),SetUp 返回后自动导出 z=Baz.C 。
Qux {
C int `import:"z"` // 声明导入 z
}
func (Qux) SetUp() { println(Qux.C) } // 同理 SetUp 被调用时,z 的值已被自动导入到 C,打印输出 Qux.C 的值为 3 。
库要做的事情就是分析 import 、export 的依赖关系,有没有循环引用之类的,并在恰当的时机拷贝 export 的值到 import 、在恰当的时机调用结构体的 SetUp 方法等。
应当提供一种拦截机制:值被 export 后,到真正传递到 import 的期间,可以安插一些 filter,对值进行操作或修改,并且这些 filter 可以设置优先级。这样方便实现各种灵活的定制。
目前上述的点都已经实现,代码提交在:
https://github.com/roy2220/depinj
思绪有点混乱,看不懂我在写啥没关系😂,github 上有 example,有兴趣跑一跑就明白了。。。欢迎讨论交流