我想为我的框架制作模型,用 go 编写,但我不知道如何以共享通用数据库交互方法的方式组合它们:保存、更新、删除。
我通常会通过为所有具体模型创建一个 Model 抽象父类来完成此操作,但 Go 没有继承。您应该使用嵌入和组合,但我不知道如何嵌入模型类并让它保存保存它的类的数据。
我看到了另一个选项,即创建一个在其中嵌入具体模型类型的模型类,但我并没有真正看到一个适用于所有模型的接口,除非它是空的。这带来了任何东西都可以被视为模型的不安全感。
做什么?
在我的项目中我做了这样的事情:
type Storable interface {
// called after unmarshalling from the database
Init() error
// called when an object is being deleted
// this is useful if the object needs to delete other objects,
// change state on a remote server, etc.
Destroy() error
// called after Init, helps separate initialization from
// sanity checks (useful to detect errors before using a potentially
// invalid object)
Validate() error
// type of this object, stored in the database in `Save` and `Update`
// so it can be read out in `Get`
Type() string
}
如果您正在使用 SQL 数据库,您可以执行以下操作:
type Schema map[string]reflect.Type
type SQLStorable interface {
Storable
Schema() Schema
}
然后在数据库中,我有这样的函数:
func Get(id string) (Storable, error)
func Save(Storable) error
func Update(id string, Storable) error
func Delete(id string) error
// register a type with the database (corresponds to the Type() in Storable)
func Register(typ string, reflect.Type)
我在数据库中保留对象的缓存:
map[string]Storable
。这允许我实现缓存逻辑以减少查找时间(不需要每次从数据库读取对象时都重建对象)。
在我的项目中,我有很多包需要与其他包中的对象进行通信。由于管理依赖链将是一场噩梦,因此我设置了一个使用数据库的消息传递系统:
type Message map[string]interface{}
func Send(id string, Message)
我在 Storable 中添加了一个
Receive
函数,它接受 Message
并返回错误。到目前为止,这已经减少了许多令人头疼的问题,并带来了更具可插拔性的设计。
我不确定这是否是“Go way”,但它避免了继承的想法并解决了问题。在数据库逻辑中,我使用大量反射从数据库中获取数据并用它填充对象。它会导致一些不幸的类型断言,但我想当试图保持抽象时这并没有什么帮助。
为什么不能使用预先存在的框架或在它们的基础上进行构建?一些例子是 GORM、SQLBoiler、XO、SQLC 等。