dpgua04022 2016-10-30 21:27
浏览 11

在GO中抽象掉持久层

So, I'm relatively new to the world of Go programming and was wondering what the community considers to be "best practice" when attempting to abstract away the persistence layer.

In DDD this is often handled through the introduction of Repositories which exposes a set of Agreggates to an Application layer.

My concern is that I've been overly "conditioned" into thinking about these problems from the perspective of Object Oriented design and would like to explore other programming paradigms.

This will also be my first attempt at developing micro-services; which is part of the reason why I'd like to keep my design as simple as possible.

  • 写回答

1条回答 默认 最新

  • douliaodun9153 2016-10-30 21:57
    关注

    I don't think there's one good answer to this question, multiple approaches may be good, one better from a specific point of view, and another being better from another point of view.

    Just try to create an interface (not in the meaning of Go interface type) that hides DB specific behavior and types, which will leave you the option to easily switch to a new db implementation later on, given that all other parts of your code strictly access the persistent layer via this DB interface.

    The DB interface should define Go model types (modeling data stored in the persistent layer), and operations on these types, e.g. load, find, save.

    As an example, modeling a user:

    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
    }
    

    And you may create an implementation (or multiple ones) of the Manager interface. An implementation using 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
    }
    

    A db.Manager instance (since it involves building a connection to a (Mongo)DB server) should be kept for as long as possible (e.g. global instance). Depending on the usage, Manager.Copy() and Manager.Clone() operations should be supported to acquire a copy or clone for short lived usage (e.g. serving an HTTP request).

    Using this example: Someone somewhere has to call mongo.New() to acquire a value of the db.Manager, but from there we only have to interact with the persistence layer via the Manager, leaving any db specific detail to the implementation.

    For example:

    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
    ", id, err)
        return
    }
    fmt.Printf("Loaded User: %+v
    ", u)
    
    评论

报告相同问题?

悬赏问题

  • ¥15 GDI处理通道视频时总是带有白色锯齿
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)
  • ¥15 自适应 AR 模型 参数估计Matlab程序
  • ¥100 角动量包络面如何用MATLAB绘制
  • ¥15 merge函数占用内存过大
  • ¥15 Revit2020下载问题
  • ¥15 使用EMD去噪处理RML2016数据集时候的原理
  • ¥15 神经网络预测均方误差很小 但是图像上看着差别太大
  • ¥15 单片机无法进入HAL_TIM_PWM_PulseFinishedCallback回调函数