Go 这种依赖注入模式是线程安全的吗?

Go 这种依赖注入模式是线程安全的吗?,go,dependency-injection,thread-safety,Go,Dependency Injection,Thread Safety,我很难想出一个干净的模式来在REST服务器中注入依赖项,从而允许我编写独立的单元测试。下面的结构似乎可以工作,但我不确定它是否是线程安全的 商店: 包装店 类型接口存储接口{ 连接() 断开连接() 用户接口用户 } //接线 类型存储结构{ db*mongo.Database } func(s*store)Connect(){ 客户端,错误:=mongo.Connect() 如果错误!=零{ log.Fatal(err.Error()) } s、 db=client.Database() }

我很难想出一个干净的模式来在REST服务器中注入依赖项,从而允许我编写独立的单元测试。下面的结构似乎可以工作,但我不确定它是否是线程安全的

商店:

包装店
类型接口存储接口{
连接()
断开连接()
用户接口用户
}
//接线
类型存储结构{
db*mongo.Database
}
func(s*store)Connect(){
客户端,错误:=mongo.Connect()
如果错误!=零{
log.Fatal(err.Error())
}
s、 db=client.Database()
}
func(s*存储)断开连接(){
s、 db.Client().Disconnect(context.TODO())
}
func(s*store)用户()接口用户{
返回&用户{s.db}
}
//从包中公开以创建存储实例
func GetStore()接口存储{
返回和存储{}
}
//用户相关
类型接口用户接口{
InsertOne(models.User)(字符串,错误)
}
类型用户结构{
db*mongo.Database
}
func(u*user)InsertOne(user models.user)(primitive.ObjectID,错误){
集合:=u.db.collection(collectionUsers)
//在数据库中持久化用户
}
服务器:

包服务器
类型服务器结构{}
func(s*服务器)启动(){
storeInstance:=store.GetStore()
storeInstance.Connect()
defer-storeInstance.Disconnect()
r:=gin.Default()
keys:=keys.GetKeys()
InitRoutes(r,storeInstance)
端口:=fmt.Sprintf(“:%s”,key.port)
r、 运行(端口)
}
func CreateInstance()*服务器{
返回&服务器{}
}
路线:

包路由
func InitRoutes(路由器*gin.Engine,存储区存储区接口存储区){
路由器。使用(中间件。Cors)
//createSubrouter创建前缀为“/user”的Gin routerGroup
用户路由(createSubrouter(“/user”,路由器),存储)
}
func userRoutes(路由器*gin.RouterGroup,store-store.InterfaceStore){
控制器:=控制器。GetUserController(存储)
router.GET(“/”,controller.GET)
}
控制器:

包控制器
类型userControllers结构{
UserService.interfaceeuser
}
func(u*userControllers)Get(c*gin.Context){
userDetails,:=u.UserService.FetchAllInformation(bson.M{“\u id”:userData.(models.User.id})
utils.RespondWithJSON(c,userDetails)
}
func GetUserController(store store.InterfaceStore)用户控制器{
userService:=services.GetUserService(存储)
返回用户控制器{
用户服务:&用户服务,
}
}
服务:

套餐服务
类型接口用户接口{
获取信息(bson.M)(*models.User,错误)
}
类型用户结构{
store.InterfaceStore
}
func(u*user)获取信息(filter bson.M)(*models.user,错误){
用户,错误:=u.store.user().FindOne(筛选器)
如果错误!=零{
返回零,错误
}
返回用户,无
}
func GetUserService(store store.InterfaceStore)用户{
返回用户{
店:店,,
}
}
通过使用接口,我可以在为控制器编写测试时模拟整个服务,并且我可以模拟整个存储来测试服务组件,而不会影响数据库


我想知道存储实例是否在代码中安全共享,因为接口不是指针。这是否意味着每次我将
存储
传递到树上时都会创建一个副本?

类型用户结构{}定义声明
存储
是实现
存储.接口存储
接口的任何东西

如果仔细观察,您将使用指针接收器实现它。这意味着接收者(指向的实例)将被共享

如果您的mock通过值类型实现它们,那么它将在方法调用时被复制,您将是安全的,但这也意味着此mock在方法调用后不会保持新状态,我猜这不是您想要的


归根结底,这并不是你如何在结构中定义它,通过值或引用,而是这些方法接受什么作为接收者。

谢谢。我没弄错吧,在
services
中,
fetchAllInformation
方法确实应该是一个指针接收器,这样存储就不会被复制,但是在我的模拟中,
fetchAllInformation
方法应该是一个值接收器,这样在测试期间方法的状态就不会被共享了?是的,这正是我要说的。如果模拟实现只使用引用接收器,那么为每个测试创建一个新的模拟实例也是可行的选择吗?@Bill_BsB,是的,它应该是可行的选择。实际上,最好在单个测试的调用之间保留状态。