【问题标题】:Abstracting away the persistence layer in GO [closed]抽象出 GO 中的持久层 [关闭]
【发布时间】:2017-03-13 00:59:43
【问题描述】:

所以,我对 Go 编程世界还比较陌生,想知道在尝试抽象出持久层时,社区认为什么是“最佳实践”。

在 DDD 中,这通常通过引入存储库来处理,该存储库将一组聚合门暴露给应用层。

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

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

【问题讨论】:

    标签: go architecture domain-driven-design microservices


    【解决方案1】:

    我认为这个问题没有一个好的答案,多种方法可能都不错,从特定角度来看一种更好,从另一个角度来看另一种更好。

    只需尝试创建一个隐藏 DB 特定行为和类型的接口(不是 Go 接口类型的含义),这将使您稍后可以轻松切换到新的 db 实现,因为所有其他部分您的代码通过此 DB 接口严格访问持久层。

    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)DB 服务器的连接)应尽可能长时间地保留(例如全局实例)。根据使用情况,应支持 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)
    

    【讨论】:

    • 这不是和仓库模式一样吗?
    • @plalx 是的,但没有人说它不能应用或者不适合在 Go 中使用。
    • “我担心的是我已经过度“适应”了从面向对象设计的角度思考这些问题,并希望探索其他编程范例”。换句话说,OP 已经知道存储库模式,但他正在寻找其他好的替代方案来抽象出 Go 中的持久性问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多