我最近一直在做一个相当大的 API 项目,里面包括很多路由规则( routes )、服务接口( services )和处理函数( handlers )等。首先,我注意到 `main.go` 文件的启动过程开始越来越臃肿。
为了避免设置全局的服务接口,我使用共享结构体( struct )将服务接口与处理函数绑定在一起。举个例子:
main.go
```go
package main
func main() {
r := gin.Default()
userRepo := models.NewUserRepo(
drives.DataStore().C("users"),
)
userHandler := handlers.NewUserHandler(userRepo)
r.GET("/api/v1/users", userHandler.FindAll)
r.Run(":8080")
}
```
user_handler.go
```go
type UserHandler struct {
userRepo *models.UserRepo
}
func NewUserHandler(userRepo *models.UserRepo) *UserHandler {
return &UserHandler{
userRepo,
}
}
func (userHandler *UserHandler) FindAll(c *gin.Context) {
users, err := userHandler.userRepo.FindAll()
if err != nil {
c.JSON(404, nil)
return
}
c.JSON(200, users)
return
}
```
这些代码工作的很好,但是,你会发现 main.go 中,我只是写了很少的启动过程,仅仅包含一个处理函数和一个持久化数据( repository )。(译注:用这种方式写代码比较麻烦且臃肿)。
于是我想用 Go 写一个容器。我找不到一个喜欢的第三方库来解决这个事情。所以,想出了下面这段代码。
```go
import(
"sync"
)
type Container struct{
mux sync.RWMutex
m map[string]interface{}
}
// Add service
func (c *Container) Add(name string, object interface{}) {
c.mux.Lock()
if c.m == nil {
c.m = make(map[string]interface{})
}
c.m[name] = object
c.mux.Unlock()
}
// Remove service
func (c *Container) Remove(name string) Container {
c.mux.Lock()
delete(c.m, name)
c.mux.Unlock()
}
// Get a service
func (c *Container) Get(name string) (object interface{}, bool) {
c.mux.RLock()
object, ok = c.m[name]
c.mux.RUnlock()
return object, ok
}
```
注意这段代码的每个方法都用了 `mutex lock` 来避免容器的并发问题。
现在代码可以这样写。。。
```go
func GetContainer() Container {
c := new(container.Container)
c.Add("user.handler", handlers.UserHandler)
return c
}
```
现在的 main.go
```go
func main() {
container := container.GetContainer()
userHandler, ok := container.Get("user.handler")
if !ok {
log.Fatal("Service not found")
}
r.GET(
"/api/v1/users",
userHandler.(*handlers.UserHandler).FindAll(),
)
}
```
_同步方面的代码参考自 itsmontoya ,向他致敬_
现在我已经将启动过程很简洁地封装成了包。我觉得一个有 PHP 语言背景的人在考虑这段语法实现时候会参考 [pimple](http://pimple.sensiolabs.org/) 框架。
我已经把这个抽象成了自己的库,实现在[这里](https://github.com/EwanValentine/Vertebrae) 。
via: https://ewanvalentine.io/writing-a-service-container-in-go/
作者:Ewan Valentine 译者:jzhongming 校对:rxcai
本文由 GCTT 原创翻译,Go语言中文网 首发。也想加入译者行列,为开源做一些自己的贡献么?欢迎加入 GCTT!
翻译工作和译文发表仅用于学习和交流目的,翻译工作遵照 CC-BY-NC-SA 协议规定,如果我们的工作有侵犯到您的权益,请及时联系我们。
欢迎遵照 CC-BY-NC-SA 协议规定 转载,敬请在正文中标注并保留原文/译文链接和作者/译者等信息。
文章仅代表作者的知识和看法,如有不同观点,请楼下排队吐槽