通过一个接口抽象出多个数据源,供存储库使用

问题描述

我正在尝试应用干净的体系结构,除其他外,我有一个数据源层和一个存储库层。

存储库使用接口与基础数据源(仅sql db atm)进行交互,但是数据源接口是针对sql数据库量身定制的,如下所示:

package datasource

import "database/sql"

type Source interface {
  open() error                                        // Open the connection

  Close()                                             // Close the connection
      
  Exec(string,...interface{}) error                  // Execute a prepared query(e.g:insert)

  Query(string,...interface{}) (*sql.Rows,error)    // Retrieve rows with a prepared query
}

我想稍后还会引入其他数据源(例如nosql dbs或外部API ...),我如何将它们全部归类在一个公共接口下,以使存储库不需要知道数据来源。

谢谢。

PS:我知道也有类似的问题,但是从存储库的角度来看,这些问题都可以解决。我正在寻找数据源方面的解决方案(例如:通用接口),因为我不希望每个来源都有单独的存储库。

解决方法

您选择的抽象级别不支持与数据库无关的实现。您期望使用SQL查询,并且返回*sql.Rows

如果要独立于数据库(包括关系数据库和NoSQL数据库),则需要使用更高的抽象级别,其中不存在诸如SQL或NoSQL查询之类的术语。

例如,如果您打算查询,加载和保存用户,则界面的相关部分可能如下所示:

type User struct {
    ID string
    // other info about users
}

type Source interface {
    GetUser(id string) (*User,error)
    SaveUser(u *User) error
    FindUsersByFirstName(firstName string) ([]*User,error)
}

此接口并不限制实现与SQL查询和相关对象一起使用,但它表示您需要执行哪些操作。应用程序的其他部分应该(必须)仅通过此界面访问数据层。所有详细信息(例如SQL查询)都属于该实现。

在继续进行此抽象之前,请先审查其优点和所需的额外工作,因为通常人们会针对不太可能的情况进行计划。如果从SQL数据库开始,则可能永远不会切换到NoSQL数据库。

您不能(不应该)有一个数据源层来支持您想要的抽象级别的所有数据库。这将需要“开发”一种与数据库无关的查询语言及其解析器,然后您需要将其翻译为特定的数据库查询。如果要支持所有数据库,最简单的方法是合并存储库和数据源层。或者放弃支持所有数据库,因为几乎99%的项目都不会切换到根本不同的数据库。