如何创建将保存我的db和redis连接的服务类型层

时间:2018-02-03 22:22:20

标签: go

我正在尝试对这个小golang应用程序进行原型设计,并希望就如何管理我的数据库和redis连接对象提供一些建议。

我想创建一个“服务层”,它将包含所有与产品相关的逻辑,因此可能是ProductService。

我希望ProductService能够引用redis和我的数据库客户端。

这个ProductService粗略地看起来是什么样的,如果我需要创建一个这样的实例并在整个应用程序中使用它,我是否在var中定义它?

func main() {

  db, err := gorm.Open("postgres", "host=localhost user=blankman dbname=blank_development sslmode=disable password=")
  if err != nil {
    log.Fatalf("Got error when connect database, the error is '%v'", err)
  }
  defer db.Close()

  redis := redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "",
    DB:       0,
  })

  pong, err := redis.Ping().Result()
  fmt.Println(pong, err)

  router := mux.NewRouter()

  router.HandleFunc("/products", GetProducts).Methods("GET")

  log.Fatal(http.ListenAndServe(":3001", router))
}

我的GetProducts处理程序有你的常规签名:

func GetProducts(w http.ResponseWriter, r *http.Request) 

我想如何将ProductsService传入此处理程序?看起来请求/响应以某种方式由MUX自动传递给此处理程序,因此不确定如何获取对ProductService的引用?

2 个答案:

答案 0 :(得分:1)

使用您需要的字段创建产品服务:

type ProductService struct {
   db *gorm.DB
   redis *redis.Client
}

使GetProducts成为ProductService的方法:

func (s *ProductService) GetProducts(w http.ResponseWriter, r *http.Request)  {
  // s.db is the database, s.redis is the redis client
}

在main中初始化ProductService。使用method values作为处理函数:

s := &ProductService{db: db, redis: redis}

router.HandleFunc("/products", s.GetProducts).Methods("GET")

方法值的替代方法是使用闭包来使函数适应处理函数:

func (s *ProductService) Handler(fn func(*ProductService, http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
        fn(s, w, r)
    }
}

使用

router.HandleFunc("/products", s.Handler(PostPoduct)).Methods("POST")

注册这样的函数:

func PostProduct(s *ProductService, w http.ResponseWriter, r *http.Request)  {
}

使用第二种方法,ProductService层可以与各个处理程序分开。

答案 1 :(得分:1)

另一种选择是避免使用服务的结构并使用闭包(使用一个关闭依赖项的函数)来构建处理程序,如下所示:

func MakeGetProductsHander(db *gorm.DB, client *redis.Client) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // Use db and client in here...
    }
}

然后像这样应用处理程序:

router.HandleFunc("/products", MakeGetProductsHander(db, client)).Methods("GET")

这会以更明确,更明显的方式将您的依赖项注入您的处理程序。

附注:将Redis客户端变量重命名为client或其他内容,因为您通过调用它来redis隐藏包名称。