使用与golang的接口和数据库抽象



我正试图弄清楚如何在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)中。但这感觉真的错了。看起来它应该是datastore/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()
}

shapes/shape.go

package shapes
type Shaper interface {
Area() float64
}

形状/圆形/圆形.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
}

形状/正方形/正方形.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
}

数据存储/数据存储.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. 
}

由于圆形和方形对象的数据库表会有所不同,因此我需要为每一个对象都有一个方法。如果我在圆形包和方形包中添加一个方法来进行插入,我就可以实现这一点。但就像我上面说的,感觉我做错了。

提前非常感谢。

类型切换是正确的做法。你的逻辑代码(你写的那个,因为以前没有其他人做过)应该对存储一无所知。

比方说,你想为请求添加一个计数器,然后决定在Redis上计数请求。那怎么办?是否也将计数器集合名称添加到Shape?

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

对于一个没有sql的数据库,有时你根本不关心模式,你只需要序列化对象并保存它

最新更新