我意识到之前已经回答了有关循环依赖的问题,但是,答案通常只是说合并包。长话短说,我有一个可以实现多种类型的接口(interface)。我想有一种方法来使用其名称选择在运行时使用其中一种类型。这也将用于序列化。我读入类的名称,然后实例化正确的类。
我使用了策略模式。有一个Base
包内接口(interface)A
.
package A
import (
"../C"
)
type Base interface {
doStuff(p C.Profile) int
}
type Operation struct {
Base Base
Data int
}
func (o *Operation) execute(p C.Profile) int {
return o.Base.doStuff(p)
}
然后,在包
B
中有实现该接口(interface)的类型。 .//file Impl1.go
package B
import (
"../C"
)
type Impl1 struct {}
func (b *Impl1 ) doStuff(p C.Profile) int {
...
}
//file Impl2.go
package B
import (
"../C"
)
type Impl2 struct {}
func (b *Impl2 ) doStuff(p C.Profile) int {
...
}
然后在包装
C
我有结构 Foo
字段类型为 Base
.该字段可以指向包 B
中的任何实现。 .我们可以在运行时选择实现。这是我最终想要序列化的结构。package C
import (
"../A"
"../B"
)
type Foo struct {
bar A.Base
baz []Profile
...
}
func (f *Foo) changeBar(name string, data int) {
switch name {
case "Impl1":
f.bar = Operation{Base: B.Impl1{}, Data: data}
case "Impl2":
f.bar = Operation{Base: B.Impl2{}, Data: data}
...
}
编辑:也在
C
包,我们有 Profile
,这就是 A
的原因和 B
包需要导入它。此代码具有循环依赖
C
-> B
-> C
.一个明显的解决方案是移动 Profile
到不同的包。但这是不可能的,因为 Profile
(以及 C
包中的许多其他类似类型)和 Foo
耦合非常紧密并且属于同一个包(在这个最小的工作示例中可能不那么明显)。这是此类问题的其他答案所暗示的,但我想学习如何使用从其他语言中学到的良好实践来使其发挥作用。另一种解决方案是以某种方式移动工厂方法
changeBar
到另一个包,并且只在 C
的外部使用它包(从而避免循环),将结果传递给 C
作为参数,但在某些情况下(特别是序列化)我实际上需要在 C
内部使用它包裹。我花了很多时间来解决这个问题,但我最终的结果是将所有内容都放在一个巨大的包中,或者将每个文件放在一个单独的包中,然后将所有内容导出。在其他编程语言中,有可能要么有这些循环依赖,要么一次从包中导入一个“类”。进去的方法是什么?
最佳答案
您可以使用类型注册表打破从 C 到 B 的依赖关系:
package C
import "A"
var TypeRegistry = map[string]func() A.Base {}
func (f *Foo) changeBar(name string, data int) {
if factory, ok:=TypeRegistry[name]; ok {
f.bar=Operation{Base:factory(),Data:data}
}
}
然后在任何包中注册您的实现:
package B
import "../C"
func init() {
C.TypeRegistry["myType"]=func() A.Base { return MyType{}}
}
关于go - golang 中的工厂方法存在循环依赖问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59413193/