【问题标题】:How to avoid dependency cycles with shared packages?如何避免共享包的依赖循环?
【发布时间】:2020-02-13 05:41:02
【问题描述】:

我知道这被问了很多,但我仍然不明白如何解决它。假设我有这个结构:

foo
- foos.go      // custom foo type
database
- database.go  // interface
- postgres.go  // implementation

database.go我需要导入foo,所以我可以saveOnDb(foo.myfoo),在foos.go我需要导入database,所以我可以database.saveOnDb(myfoo)

由于导入周期,这无法编译。正确的设计应该是什么?

【问题讨论】:

  • 将你的类型放在一个单独的共享包中,没有依赖关系。
  • 为什么它们需要是单独的包,或者你为什么要在两个不同的包中做同样的事情?
  • @JimB 我有很多包,它们都需要在数据库中保存东西。你是说最好将database 接口分解成每个只保存自己的东西的包,而不是只有一个集中的数据库包?
  • @Flimzy 谢谢,这是有道理的。阅读您的其他评论,我想知道为什么将不同的包耦合到共享类型包比跨包传播 db 代码更好?
  • 为什么foo 打电话给database.saveOnDb?通常你会有一些依赖于这两个包的东西,这样它就可以使用foo 类型并将其保存到数据库中。但信息如此之少,很难提供很多建议。

标签: go design-patterns circular-dependency


【解决方案1】:

数据库不应该依赖foo,它应该足够抽象。

你可以使用接口而不是saveOnDb(foo.myfoo) 吗?

type somefoo interface{}

saveOnDb(somefoo)

然后调用它

database.saveOnDb(myfoo)

【讨论】:

    【解决方案2】:

    另一种解决方法是让 foo 负责保存到数据库,因此 foo 调用 db 包,而其他包只调用 foo.Save 而不关心 db 包。所以而不是:

    database.saveOnDb(myfoo)
    

    如果要保存 foo 的字段,请在 foo 的实例上使用此方法,该实例使用数据库包在内部保存:

    foo.Save()
    

    还有你可能想要的 foos(或 foo)包中

    foos.Create()
    foos.Find()
    foos.FindAll() 
    

    知道所有关于 foo 以及如何返回它们 - db 包不应该知道这一点,所以它不应该导入 foo。

    您的数据库包绝对不应该知道特定类型,它应该知道与数据库通信。如果您更喜欢更通用的解决方案,还可以查看一些 orms(但这需要大量使用 interface{})。

    【讨论】:

    • 这是朝错误方向迈出的一步。这意味着跨包传播你的数据库代码。这不是好的设计。
    • db 代码在 db 包中。关于您的类型的代码,包括实例化它们,应该与 IMO 的类型(无论它们住在哪里)一起使用。你如何构建你的包是一个品味和问题域的函数,没有一种真正的方式来构建 Go 包。
    • 没有“一种真正的方式”,但有明显的设计气味。跨包传播数据库代码是最臭的,也是最明显的违反 SOLID 原则的行为之一。当然,如果您不关心或不想要干净的代码,那就随心所欲。
    • 那你怎么建议foo知道怎么写数据库呢?
    • 那么你的foo.Create() 等人只是db.XXX 的包装器,所以你还没有解决任何问题。您只添加了重定向。
    猜你喜欢
    • 1970-01-01
    • 2013-02-06
    • 1970-01-01
    • 2012-02-15
    • 2013-04-02
    • 2012-08-10
    • 1970-01-01
    • 2016-08-09
    相关资源
    最近更新 更多