go - 这种依赖注入模式线程安全吗?
问题描述
我很难想出一个干净的模式来在 REST 服务器中注入依赖项,从而允许我编写独立的单元测试。下面的结构似乎有效,但我不确定它是否是线程安全的。
店铺:
package store
type InterfaceStore interface {
Connect()
Disconnect()
User() interfaceUser
}
// Wiring up
type store struct {
db *mongo.Database
}
func (s *store) Connect() {
client, err := mongo.Connect()
if err != nil {
log.Fatal(err.Error())
}
s.db = client.Database()
}
func (s *store) Disconnect() {
s.db.Client().Disconnect(context.TODO())
}
func (s *store) User() interfaceUser {
return &user{s.db}
}
// Exposed from the package to create a store instance
func GetStore() InterfaceStore {
return &store{}
}
// User related
type interfaceUser interface {
InsertOne(models.User) (string, error)
}
type user struct {
db *mongo.Database
}
func (u *user) InsertOne(user models.User) (primitive.ObjectID, error) {
collection := u.db.Collection(collectionUsers)
// persisting user in DB
}
服务器:
package server
type server struct{}
func (s *server) Start() {
storeInstance := store.GetStore()
storeInstance.Connect()
defer storeInstance.Disconnect()
r := gin.Default()
keys := keys.GetKeys()
routes.InitRoutes(r, storeInstance)
port := fmt.Sprintf(":%s", keys.PORT)
r.Run(port)
}
func CreateInstance() *server {
return &server{}
}
路线:
package routes
func InitRoutes(router *gin.Engine, store store.InterfaceStore) {
router.Use(middlewares.Cors)
// createSubrouter creates a Gin routerGroup with the prefix "/user"
userRoutes(createSubrouter("/user", router), store)
}
func userRoutes(router *gin.RouterGroup, store store.InterfaceStore) {
controller := controllers.GetUserController(store)
router.GET("/", controller.Get)
}
控制器:
package controllers
type userControllers struct {
UserService services.InterfaceUser
}
func (u *userControllers) Get(c *gin.Context) {
userDetails, _ := u.UserService.FetchAllInformation(bson.M{"_id": userData.(models.User).ID})
utils.RespondWithJSON(c, userDetails)
}
func GetUserController(store store.InterfaceStore) userControllers {
userService := services.GetUserService(store)
return userControllers{
UserService: &userService,
}
}
服务:
package services
type InterfaceUser interface {
FetchAllInformation(bson.M) (*models.User, error)
}
type user struct {
store store.InterfaceStore
}
func (u *user) FetchAllInformation(filter bson.M) (*models.User, error) {
user, err := u.store.User().FindOne(filter)
if err != nil {
return nil, err
}
return user, nil
}
func GetUserService(store store.InterfaceStore) user {
return user{
store: store,
}
}
通过使用接口,我可以在为控制器编写测试时模拟整个服务,并且我可以模拟整个存储来测试服务组件而无需访问数据库。
我想知道商店实例是否在代码之间安全共享,因为接口不是指针。这是否意味着store
每次我将它向下传递时都会创建一个副本?
解决方案
type user struct {}
定义状态store
是实现store.InterfaceStore
接口的任何东西。
如果你仔细看,你正在用指针接收器来实现它。这意味着(由 the 指向的实例)接收器将被共享。
如果你的模拟通过值类型实现它们,它将在方法调用时被复制,你会很安全,但这也意味着这个模拟在方法调用后不会保持新状态,我猜这不是你的想。
归根结底,这不是关于你如何在结构中定义它,按值或按引用,而是方法接受什么作为接收者。
推荐阅读
- php - 管理员守卫中的laravel广播
- sql-server - 将多个 CSV 文件加载到 MSSQL 中的多个表中
- php - 如何取消设置会话项目计数
- laravel - 后端和前端的性能与安全性
- kubernetes - 如何更改正在运行的 pod 名称?
- r - 应用程序无法在 R Shiny 中启动(以代码 1 退出)
- excel - Excel VBA代码从网站获取数据
- mysql - 在函数节点中查询-red
- javascript - TypeError:无法读取未定义的属性“id”(message.mentions.users.first())
- c++ - connect() 在连接被拒绝时挂起很长时间