我应该避免在 golang 中使用单例包吗?

bod*_*ser 5 singleton global-variables go

目前我有一个包含store以下内容的包:

package store

var (
    db *Database
)

func Open(url string) error {
    // open db connection
}

func FindAll(model interface{}) error {
    // return all entries
}

func Close() {
    // close db connection
}
Run Code Online (Sandbox Code Playgroud)

这允许我在完成store.FindAll后可以从其他包中使用。store.Openmain.go

然而,据我所知,到目前为止,大多数包更喜欢提供一个您需要自己初始化的结构。使用这种全局方法的情况很少。

这种方法有哪些缺点?我应该避免吗?

小智 5

  1. 您无法同时实例化到 2 个存储的连接。
  2. 您无法使用 gomock 等方便的工具在依赖代码的单元测试中轻松模拟存储。


Soh*_*neh 4

标准http包有一个ServerMux用于通用用例的包,但为了方便起见,还有一个ServerMux名为DefaultServerMuxhttp://golang.org/pkg/net/http/#pkg-variables)的默认实例。这样,当您调用它时,http.HandleFunc它就会在默认多路复用器上创建处理程序。log您可以找到许多其他包中使用的相同方法。这本质上是您的“单例”方法。

但是,我认为在您的用例中遵循该模式不是一个好主意,因为Open无论默认数据库如何,用户都需要调用。而且,正因为如此,使用默认实例并没有真正的帮助,反而会变得不那么方便:

d := store.Open(...)
defer d.Close()
d.FindAll(...)
Run Code Online (Sandbox Code Playgroud)

比以下内容更容易编写和阅读:

store.Open(...)
defer store.Close()
store.FindAll(...)
Run Code Online (Sandbox Code Playgroud)

而且,还存在语义问题:如果有人调用Open两次会发生什么:

store.Open(...)
defer store.Close()
...
store.Open(...)
store.FindAll(...) // Which db is this referring to?
Run Code Online (Sandbox Code Playgroud)