【发布时间】:2017-08-12 23:10:50
【问题描述】:
我正在尝试通过创建一个能够创建投影的简单事件存储来学习如何使用 Go。我被困在如何使用包含混合类型结构的切片和映射上。这样做的重点是,我希望开发人员根据需要使用各种字段创建尽可能多的实现 IEntity 和 IEvent 的结构。
我来自 JavaScript/Node.js 背景,具有一些 C/C++/Java 的基本知识,我可能在这里寻找很多类/继承模式,并且需要一些关于如何在 Go 中获得相同功能的帮助.
package main
import (
"sync"
"time"
uuid "github.com/satori/go.uuid"
)
// IEntity describes an entity, a struct that is the sum of all events resolved in a chronological order
type IEntity interface {
}
// IProjection describes the interface for a projection struct
type IProjection interface {
Lock()
Unlock()
Get(id uuid.UUID) IEntity
Set(id uuid.UUID, entity IEntity)
GetLastEventTime() time.Time
Append(event IEvent)
}
// IEvent describes the interface for a event, any event added to the system needs to implement this interface
type IEvent interface {
Resolve(projection IProjection)
}
// EventVault is the base struct that keeps all the events and allows for projections to be created
type EventVault struct {
sync.Mutex
events []IEvent
}
// Append adds a IEvent to the projection and runs that events IEvent.Resolve method
func (vault *EventVault) Append(event IEvent) {
vault.Lock()
defer vault.Unlock()
vault.events = append(vault.events, event)
}
// Project creates a projection with entities from all events up until the choosen end time
func (vault *EventVault) Project(endTime time.Time, projection IProjection) IProjection {
lastEventTime := projection.GetLastEventTime()
for index := range vault.events {
event := vault.events[index]
if event.Time.After(lastEventTime) && event.Time.Before(endTime) {
projection.Append(event)
}
}
return projection
}
// Projection caculates and stores a projection of the events appended to it with the Append method
type Projection struct {
sync.Mutex
events []IEvent
entities map[uuid.UUID]IEntity
}
// Get returns an IEntity struct from an id (for use in the IEvent.Resolve method)
func (projection *Projection) Get(id uuid.UUID) IEntity {
return projection.entities[id]
}
// Set add a IEntity to the projection (for use in the IEvent.Resolve method)
func (projection *Projection) Set(id uuid.UUID, entity IEntity) {
projection.entities[id] = entity
}
// GetLastEventTime returns the time for the event that was added last
func (projection *Projection) GetLastEventTime() time.Time {
event := projection.events[len(projection.events)-1]
if event == nil {
return time.Unix(0, 0)
}
return event.Time
}
// Append adds a IEvent to the projection and runs that events IEvent.Resolve method
func (projection *Projection) Append(event IEvent) {
projection.Lock()
projection.events = append(projection.events, event)
event.Resolve(projection)
projection.Unlock()
}
// ------------------ Below is usage of above system ------------------
// PlayerEntity is a sample entity that can be used for testing
type PlayerEntity struct {
ID uuid.UUID
Name string
Birthday time.Time
UpdatedAt time.Time
}
// AddPlayerEvent is a sample event that can be used for testing
type AddPlayerEvent struct {
ID uuid.UUID
Time time.Time
Name string
}
// Resolve will create a new PlayerEntity and add that to the projection
func (event *AddPlayerEvent) Resolve(projection IProjection) {
player := PlayerEntity{ID: uuid.NewV4(), Name: event.Name, UpdatedAt: event.Time}
projection.Set(player.ID, &player)
}
// SetBirthdayPlayerEvent is a sample event that can be used for testing
type SetBirthdayPlayerEvent struct {
ID uuid.UUID
Time time.Time
Birthday time.Time
}
// Resolve will change the name on a PlayerEntity
func (event *SetBirthdayPlayerEvent) Resolve(projection IProjection) {
player := *projection.Get(event.ID)
player.Birthday = event.Birthday
player.UpdatedAt = event.Time
}
func main() {
vault := EventVault{}
event1 := AddPlayerEvent{ID: uuid.NewV4(), Time: time.Now(), Name: "Lisa"}
vault.Append(&event1)
birthday, _ := time.Parse("2006-01-02", "2017-03-04")
event2 := SetBirthdayPlayerEvent{ID: event1.ID, Time: time.Now(), Birthday: birthday}
vault.Append(&event2)
}
我得到的错误是
./main.go:47: event.Time undefined (type IEvent has no field or method Time)
./main.go:79: event.Time undefined (type IEvent has no field or method Time)
./main.go:122: invalid indirect of projection.Get(event.ID) (type IEntity)
结构类型可能丢失了,所以我需要另一种存储方式来将它们放入映射和切片中,但是如何?
【问题讨论】:
-
我们是否应该在屏幕上滑动手指直到我们数到 122 行,或者您想指出问题出在哪里? :)
-
如果我理解正确的话,你可以将
Time() time.Time添加到你的IEvent界面。此外,您需要在结构中实现一个名为Time() time.Time的方法,并将给定的第 47,79 行更新为event.Time()。 -
是的,但我看到了两个问题,一个是我必须为所有属性添加一个 getter/setter,另一个是如果我添加一个实体,例如调用具有属性 Kind string、Branches []Branch 等的 TreeEntity,它们将具有不同的 getter/setter,因为它们具有不同的属性,因此会破坏 Resolve 方法。 :/ 我习惯于松散地输入语言 :/
标签: inheritance go data-structures struct interface