所以,我对Go编程世界相对较新,并且在想要抽象出持久层时,想知道社区认为什么是“最佳实践”。
在DDD中,这通常通过引入存储库来处理,存储库将一组Agreggates暴露给Application层。
我担心的是,从面向对象设计的角度来看,我已经过度“习惯”思考这些问题,并希望探索其他编程范式。
这也是我开发微服务的第一次尝试;这也是我希望尽可能简化设计的部分原因。
答案 0 :(得分:1)
我认为这个问题没有一个好的答案,多种方法可能是好的,从特定的角度来看更好,而另一种观点则更好。
尝试创建一个隐藏数据库特定行为和类型的接口(不是Go接口类型的含义),这将使您可以选择在以后轻松切换到新的数据库实现,因为所有其他部分您的代码通过此DB接口严格访问持久层。
数据库接口应该定义Go模型类型(存储在持久层中的建模数据),以及对这些类型的操作,例如:加载,查找,保存。
例如,为用户建模:
package db
type ID int64
type User struct {
ID ID
Name string
}
// Manager contains the operations that involve the persistence layer.
type Manager interface {
LoadUser(id ID) (*User, error)
SaveUser(u *User) error
FindUsersByName(name string) ([]*User, error)
Close() error
}
您可以创建Manager
接口的实现(或多个)。使用MongoDB的实现:
package mongo
import (
"db"
"gopkg.in/mgo.v2"
)
// manager is a db.Manager implementation that uses MongoDB
type manager struct {
// unexported fields, e.g. MongoDB session:
sess *mgo.Sess
}
func (m *manager) LoadUser(id db.ID) (*db.User, error) { ... }
func (m *manager) SaveUser(u *db.User) error { ... }
func (m *manager) FindUsersByName(name string) ([]*db.User, error) { ... }
func (m *manager) Close() error {
m.sess.Close()
return nil
}
func New(mongoURL string) (db.Manager, error) {
// Create, initialize your manager, and return it:
sess, err := mgo.Dial(url)
if err != nil {
return nil, err
}
return &manager{sess: sess}, nil
}
db.Manager
实例(因为它涉及与(Mongo)数据库服务器建立连接)应该尽可能长时间地保留(例如全局实例)。根据使用情况,应支持Manager.Copy()
和Manager.Clone()
操作以获取短期使用的副本或克隆(例如,提供HTTP请求)。
使用此示例:某人必须致电mongo.New()
以获取db.Manager
的值,但从那里我们只需要通过Manager
与持久层进行交互,任何数据库特定的实现细节。
例如:
var mgr db.Manager
var err error
mgr, err = mongo.New("<mongodburl>")
if err != nil {
log.Printf("Could not connect to db:", err)
return
}
defer mgr.Close()
id := 123456
u, err := mgr.LoadUser(id)
if err != nil {
log.Printf("Failed to load user [id: %v]: %v\n", id, err)
return
}
fmt.Printf("Loaded User: %+v\n", u)