我将应用程序从Play
(Scala)移植到Go
,并想知道如何实现依赖项注入。在Scala中我使用了蛋糕模式,而在Go
中,我实现了一个DAO
接口以及一个Mongo的实现。
下面是我尝试实现一种模式,让我根据需要更改DAO
实现(例如测试,不同的数据库等):
1。 entity.go
package models
import (
"time"
"gopkg.in/mgo.v2/bson"
)
type (
Entity struct {
Id bson.ObjectId `json:"id,omitempty" bson:"_id,omitempty"`
CreatedAt time.Time `json:"createdAt,omitempty" bson:"createdAt,omitempty"`
LastUpdate time.Time `json:"lastUpdate,omitempty" bson:"lastUpdate,omitempty"`
}
)
2。 user.go
package models
import (
"time"
)
type (
User struct {
Entity `bson:",inline"`
Name string `json:"name,omitempty" bson:"name,omitempty"`
BirthDate time.Time `json:"birthDate,omitempty" bson:"birthDate,omitempty"`
}
)
第3。 dao.go
package persistence
type (
DAO interface {
Insert(entity interface{}) error
List(result interface{}, sort string) error
Find(id string, result interface{}) error
Update(id string, update interface{}) error
Remove(id string) error
Close()
}
daoFactory func() DAO
)
var (
New daoFactory
)
4。 mongoDao.go (数据库信息和集合名称是硬编码的,因为它只是一个例子)
package persistence
import (
"fmt"
"time"
"errors"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"github.com/fatih/structs"
"cmd/server/models"
)
type (
mongoDAO struct{
session *mgo.Session
}
)
func NewMongoDAO() DAO {
dialInfo := &mgo.DialInfo{
Addrs: []string{"localhost:27017"},
Timeout: 60 * time.Second,
Database: "test",
}
session, err := mgo.DialWithInfo(dialInfo)
if err != nil {
panic(err)
}
session.SetMode(mgo.Monotonic, true)
return &mongoDAO{session}
}
func (dao *mongoDAO) Insert(entity interface{}) error {
doc := entity.(*models.User)
doc.Id = bson.NewObjectId()
doc.CreatedAt = time.Now().UTC()
doc.LastUpdate = time.Now().UTC()
return dao.session.DB("test").C("users").Insert(doc)
}
func (dao *mongoDAO) List(result interface{}, sort string) error {
return dao.session.DB("test").C("users").Find(nil).Sort(sort).All(result)
}
func (dao *mongoDAO) Find(id string, result interface{}) error {
if !bson.IsObjectIdHex(id) {
return errors.New(fmt.Sprintf("%s is not a valid hex id", id))
}
oid := bson.ObjectIdHex(id)
return dao.session.DB("test").C("users").FindId(oid).One(result)
}
func (dao *mongoDAO) Update(id string, update interface{}) error {
if !bson.IsObjectIdHex(id) {
return errors.New(fmt.Sprintf("%s is not a valid hex id", id))
}
oid := bson.ObjectIdHex(id)
doc := update.(*models.User)
doc.LastUpdate = time.Now().UTC()
return dao.session.DB("test").C("users").Update(oid, bson.M{"$set": structs.Map(update)})
}
func (dao *mongoDAO) Remove(id string) error {
if !bson.IsObjectIdHex(id) {
return errors.New(fmt.Sprintf("%s is not a valid hex id", id))
}
oid := bson.ObjectIdHex(id)
return dao.session.DB("test").C("users").RemoveId(oid)
}
func (dao *mongoDAO) Close() {
dao.session.Close()
}
func init() {
New = NewMongoDAO
}
最后,以下是我如何使用上述类型:
5。 userController.go
package controllers
import (
"net/http"
"github.com/labstack/echo"
"cmd/server/models"
"cmd/server/persistence"
)
type (
UserController struct {
dao persistence.DAO
}
)
func NewUserController(dao persistence.DAO) *UserController {
return &UserController{dao}
}
func (userController *UserController) CreateUser() echo.HandlerFunc {
return func(context echo.Context) error {
user := &models.User{}
if err := context.Bind(user); err != nil {
return err
}
if err := userController.dao.Insert(user); err != nil {
return err
}
return context.JSON(http.StatusCreated, user)
}
}
func (userController *UserController) UpdateUser() echo.HandlerFunc {
return func(context echo.Context) error {
user := &models.User{}
if err := context.Bind(user); err != nil {
return err
}
id := context.Param("id")
if err := userController.dao.Update(id, user); err != nil {
return err
}
return context.JSON(http.StatusOK, user)
}
}
....
上面的代码很好90%... mongoDao.go
中只有方法Insert
和Update
的问题,编译器强制我输入输入{{ 1}}到特定类型(entity
),但是这使我无法使用适用于所有类型的通用*models.User
组件。我该如何解决这个问题?
答案 0 :(得分:1)
这种概括
DAO interface {
Insert(entity interface{}) error
看起来过头了
你们都向*models.User
断言mongo
doc := entity.(*models.User)
并做
user := &models.User{}
userController.dao.Insert(user)
使用通用DAO接口时。 为什么不准确定义界面?
DAO interface {
Insert(entity *models.User) error
答案 1 :(得分:1)
如何创建为Entity结构实现的接口?
type Entitier interface {
GetEntity() *Entity
}
实现只会返回一个指向自身的指针,您现在可以在DAO的Insert
和Update
方法中使用它。这还有一个额外的好处,让您在DAO方法的声明中更具体。您现在可以说他们采用interface{}
而不是简单地声明他们采用任意Entitier
作为参数。
像这样:
func (dao *mongoDAO) Update(id string, update Entitier) error
以下是我的意思的最小完整示例:
http://play.golang.org/p/lpVs_61mfM
希望这会给你一些想法!一旦确定要使用的模式,您可能需要调整Entity
/ Entitier
/ GetEntity
的命名,以确定样式和清晰度。