golang 中的工厂方法存在循环依赖问题

我意识到之前已经回答了有关循环依赖的问题,但是,答案通常只是说合并包。长话短说,我有一个可以实现多种类型的接口。我想有一种方法来使用其名称选择在运行时使用其中一种类型。这也将用于序列化。我读入类的名称,然后实例化正确的类。


我使用了策略模式。Basepackage 中有一个接口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)

}

然后,在 package 中有实现该接口的类型B。


//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一个类型为 struct 的字段Base。该字段可以指向 package 中的任何实现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这就是包需要导入它的原因。AB


此代码具有循环依赖关系C-> B-> C。一个明显的解决方案是移动Profile到不同的包。但这是不可能的,因为Profile(以及包中的许多其他类似类型C)并且Foo非常紧密地耦合并且属于同一个包(在这个最小的工作示例中可能不那么明显)。这是此类问题的其他答案所暗示的,但我想学习如何使用从使用其他语言中学到的良好实践来使其发挥作用。


另一种解决方案是以某种方式将工厂方法移动changeBar到另一个包并仅在包外部使用它C(从而避免循环),将其结果C作为参数传递,但在某些情况下(特别是序列化)我实际上需要它在C包装的内侧。


我花了很多时间来解决这个问题,但我最终的结果是要么将所有内容放在一个巨大的包中,要么将每个文件放在一个单独的包中并导出所有内容。在其他编程语言中,有可能要么有这些循环依赖,要么一次从包中导入一个“类”。进去的方法是什么?


慕斯王
浏览 185回答 1
1回答

临摹微笑

您可以使用类型注册表打破从 C 到 B 的依赖关系:package Cimport "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 Bimport "../C"func init() {   C.TypeRegistry["myType"]=func() A.Base { return MyType{}}}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go