如何在Go中创建一个模型

huangapple go评论72阅读模式
英文:

How to make a model in Go

问题

我想为我的Go框架创建模型,但我不确定如何以一种共享常见数据库交互方法的方式组合它们:保存、更新、删除。

通常我会通过创建一个抽象的Model父类来实现,但Go没有继承。相反,你应该使用嵌入和组合,但我不知道如何嵌入一个模型类并保存它所持有的数据。

我看到另一种选择是创建一个模型类,在其中嵌入一个具体的模型类型,但我真的看不到一个适用于所有模型的接口,除非它是空的。这会带来任何东西都可以被视为模型的不安全性。

怎么办?

英文:

I want to make models for my framework, written in go, and I'm not sure how to compose them in a way that shares the common database interaction methods: save, update, delete.

I would normally do this by creating a Model abstract parent class to all concrete models, but Go doesn't have inheritance. You're supposed to use embedding and composition instead, but I don't see how I can embed a model class and have it save the data of the class holding it.

I see the other option, of creating a model class that embeds a concrete model type within it, but I don't really see an interface that would apply to all the models unless it was empty. That brings with it the insecurity that anything can be considered a model.

What do?

答案1

得分: 4

在我的项目中,我会做类似这样的事情:

type Storable interface {
    // 从数据库反序列化后调用
    Init() error
    // 当对象被删除时调用
    // 如果对象需要删除其他对象、更改远程服务器上的状态等,这很有用
    Destroy() error
    // 在 Init 之后调用,有助于将初始化与
    // 检查合法性分开(在使用可能无效的对象之前检测错误很有用)
    Validate() error
    // 对象的类型,在 `Save` 和 `Update` 中存储在数据库中
    // 这样可以在 `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
// 向数据库注册一个类型(对应于 Storable 中的 Type())
func Register(typ string, reflect.Type)

我在数据库中保留了一个对象的缓存:map[string]Storable。这使我能够实现缓存逻辑以减少查找时间(不需要每次从数据库读取时都重新构建对象)。

在我的项目中,我有很多需要与其他包中的对象交互的包。由于管理依赖链将是一场噩梦,所以我建立了一个使用数据库的消息系统:

type Message map[string]interface{}
func Send(id string, Message)

我还在 Storable 中添加了一个 Receive 函数,它接受一个 Message 并返回一个错误。到目前为止,这减少了很多麻烦,并导致了更具可插拔性的设计。

我不确定这是否是“Go 的方式”,但它避免了继承的概念并解决了问题。在数据库逻辑中,我使用了大量的反射来从数据库中获取数据并填充对象。这导致了一些不幸的类型断言,但我想在保持抽象的同时,这是无法避免的。

英文:

In my projects I do something like this:

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
}

If you're working with an SQL database, you could do something like this:

type Schema map[string]reflect.Type

type SQLStorable interface {
    Storable
    Schema() Schema
}

Then in the database, I have functions like this:

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)

I keep a cache of objects in the database: map[string]Storable. This allows me to implement caching logic to reduce lookup times (don't need to reconstruct objects each time it's read from the database).

In my project, I have lots of packages that need to talk with objects from other packages. Since managing dependency chains would be a nightmare, I've set up a messaging system that uses the database:

type Message map[string]interface{}
func Send(id string, Message)

And I've added a Receive function to Storable that takes a Message and returns an error. This has reduced many headaches so far and has lead to a more pluggable design.

I'm not sure if this is the "Go way", but it avoids the idea of inheritance and solves the problem. In the database logic, I use tons of reflection to grab the data from the database and populate an object with it. It leads to some unfortunate type assertions, but I guess that can't really be helped when trying to keep things abstract.

huangapple
  • 本文由 发表于 2013年7月21日 09:46:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/17768322.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定