使用golang和数据库抽象接口

时间:2017-10-24 02:49:55

标签: go interface sqlite database-abstraction

我试图找出如何在Go中构建数据存储区抽象。我想我理解接口的基础知识。但是,我遇到的问题是所有在线示例都只显示最简单的情况,除此之外没什么。

我想要做的是弄清楚SQL代码的放置方式和位置。我试图编写最简单的代码,可以说明我想要做的事情(是的,没有错误代码,是的,路径结构不是惯用的)。我有一个包含两个表的数据库。一个存储圆圈,一个存储广场。我有Go中的对象来制作这些。我的目录结构是:

project/main.go
project/test.db
project/shapes/shape.go
project/shapes/circle/circle.go
project/shapes/square/square.go
project/datastore/datastore.go
project/datastore/sqlite3/sqlite3.go

我能想到如何使这项工作的唯一方法是将SQL INSERT和SELECT代码放在实际的形状文件(circle.go和square.go)中。但这感觉非常错误。它似乎应该是数据存储区/ sqlite3包的一部分。我只是不知道如何做这项工作。以下是我到目前为止的情况:

main.go

package main

import (
    "fmt"
    "project/datastore/sqlite3"
    "project/shapes/circle"
    "project/shapes/square"
)

func main() {
    c := circle.New(4)
    area := c.Area()
    fmt.Println("Area: ", area)

    s := square.New(12)
    area2 := s.Area()
    fmt.Println("Area: ", area2)

    db := sqlite3.New("test.db")
    db.Put(c)
    db.Close()
}

形状/ shape.go

package shapes

type Shaper interface {
    Area() float64
}

形状/圈/ circle.go

package circle

import (
    "project/shapes"
)

type CircleType struct {
    Radius float64
}

func New(radius float64) shapes.Shaper {
    var c CircleType
    c.Radius = radius
    return &c
}

func (c *CircleType) Area() float64 {
    area := 3.1415 * c.Radius * c.Radius
    return area
}

形状/平方/ square.go

package square

import (
    "project/shapes"
)

type SquareType struct {
    Side float64
}

func New(side float64) shapes.Shaper {
    var s SquareType
    s.Side = side
    return &s
}

func (s *SquareType) Area() float64 {
    area := s.Side * s.Side
    return area
}

数据存储/ datastore.go

package datastore

import (
    "project/shapes"
)

type ShapeStorer interface {
    Put(shape shapes.Shaper)
    Close()
}

数据存储/ sqlite3的/ sqlite3.go

package sqlite3

import (
    "database/sql"
    _ "github.com/mattn/go-sqlite3"
    "log"
    "project/datastore"
    "project/shapes"
)

type Sqlite3DatastoreType struct {
    DB *sql.DB
}

func New(filename string) datastore.ShapeStorer {
    var ds Sqlite3DatastoreType

    db, sqlerr := sql.Open("sqlite3", filename)
    if sqlerr != nil {
        log.Fatalln("Unable to open file due to error: ", sqlerr)
    }
    ds.DB = db

    return &ds
}

func (ds *Sqlite3DatastoreType) Close() {
    err := ds.DB.Close()
    if err != nil {
        log.Fatalln(err)
    }
}

func (ds *Sqlite3DatastoreType) Put(shape shapes.Shaper) {
    log.Println("Help")
    // here you could either do a switch statement on the object type
    // or you could do something like shape.Write(), if Write() was defined
    // on the interface of shape/shapes.go Shaper interface and then
    // implemented in the Square and Circle objects. 
}

由于Circle和Square对象的数据库表不同,因此我需要为每个对象设置一个方法。如果我将方法添加到circle包和square包来进行插入,我可以使用它。但就像我上面说的那样,感觉我做错了。

非常感谢。

1 个答案:

答案 0 :(得分:0)

键入开关是正确的做法。 你的逻辑代码(你写的那个,因为之前没有其他人做过)应该对存储一无所知。

假设您要为请求添加计数器,并决定在Redis上计算请求数。然后怎样呢?将计数器集合名称添加到Shape中吗?

然后你应该创建一个新的ShapeStorer作为装饰器,并在put方法中调用Redis ShapeStorer和sqlite ShapeStorer。

对于无SQL数据库,您有时根本不关心模式,只需序列化对象并保存即可。