在GO

时间:2016-10-30 21:27:59

标签: go architecture domain-driven-design microservices

所以,我对Go编程世界相对较新,并且在想要抽象出持久层时,想知道社区认为什么是“最佳实践”。

在DDD中,这通常通过引入存储库来处理,存储库将一组Agreggates暴露给Application层。

我担心的是,从面向对象设计的角度来看,我已经过度“习惯”思考这些问题,并希望探索其他编程范式。

这也是我开发微服务的第一次尝试;这也是我希望尽可能简化设计的部分原因。

1 个答案:

答案 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)