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

标签 go architecture

我意识到之前已经回答了有关循环依赖的问题,但是,答案通常只是说合并包。长话短说,我有一个可以实现多种类型的接口(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/

相关文章:

rest - beego 找不到 Controller

java - 针对大型数据集存储和匹配名称的有效方法

python - 我的 Controller 逻辑在 Django 中放在哪里?

unit-testing - Golang 接口(interface)和模拟

mongodb - 将结构与 mgo 结果匹配

go - html 未在电子邮件 golang 中翻译

go - HTTP 处理程序中参与者模式的好处

c++ - 服务器到客户端通信架构

ios - 阻止回调或协议(protocol)在 VIPER 中的 DataManager 和交互器之间传递信息?

architecture - 使用领域驱动设计进行建模时,我应该将应用程序特定的东西放在哪里?