我正在尝试使用Scala进行事件采购(我在这两个领域都是新手)。
我希望尽可能保持一切不变,包括聚合根。 作为基础,我遵循Greg Young的ES和CQRS(https://github.com/gregoryyoung/m-r的示例,在C#中实现)并将此代码“翻译”为Scala。
问题是关于事件存储中的对象重生:
由于我的聚合根是不可变的,因此对于特定实体的每个事件,都会创建新对象。因此,例如,要重新生成具有100个事件的实体,应创建此实体的100个实例,最后一个实例将是最终状态。
效率高还是开销过高?
(我认为重新生成的最大事件数将为100,因为我将存储快照)。
这是我的代码:
活动特质
trait Event {
}
聚合的基类
abstract class AggregateRoot {
...
// HERE ENTITY IS REGENERATED FROM EVENTS AND EACH TIME NEW INSTANCE IS CREATED FOR EACH ENTITY
def loadFromHistory(history: Seq[Event]): AggregateRoot = {
var aggregate = this
history.foreach(e => aggregate = applyChange(e, false))
aggregate
}
def applyChange(event: Event, isNew: Boolean): AggregateRoot
...
}
产品汇总
case class Product(id: Long, name: String, status: Int, uncommittedChanges: Seq[Event]) extends AggregateRoot {
def changeName(name: String): Product = {
applyChange(ProductNameChangedEvent(id = this.id, name = name))
}
def applyChange(event: Event, isNew: Boolean = true): Product = {
val changedProduct = event match {
case e: ProductCreatedEvent => applyChange(e)
case e: ProductNameChangedEvent => applyChange(e)
case _ => throw new Exception("No event applier")
}
// ALSO HERE I'M COPING ALL THE LOCAL (NEW) CHANGES (THAT ARE NOT STORED IN EVENT STORE YET)
if (isNew) changedProduct.copy(uncommittedChanges = uncommittedChanges :+ event) else changedProduct
}
def applyChange(event: ProductCreatedEvent): Product = {
this.copy(id = event.id, name = event.name)
}
def applyChange(event: ProductNameChangedEvent): Product = {
this.copy(id = event.id, name = event.name)
}
...
}
答案 0 :(得分:1)
嗯......当你谈到效率时,它总会归结为数据结构的选择以及你如何优化?
在这种特殊情况下,Product
看起来像这样,
case class Product(id: Long, name: String, status: Int, changes: Seq[Event])
当您在changes
累积事件时,您的效率将由此处的数据结构决定。你不能只留下一般Seq
。
现在有一个重要的问题你应该问一下 - 你对changes
有什么用例?
嗯......除了所有不为人知的事情......我可以看到,只要您收到新活动,就要将其添加到changes
。这意味着如果您收到的频繁事件多于您需要优化将其添加到changes
所以......让我们假设您正在使用changes: List[Event]
,
现在,您必须使用prepend
这是一个恒定时间 - C而不是append
,即O(n)。
// so this line
if (isNew) changedProduct.copy(changes = changes :+ event) else changedProduct
// will have to changed to
if (isNew) changedProduct.copy(changes = event +: changes) else changedProduct
但现在你changes
列表将包含颠倒顺序的事件......所以你必须记住,在重建你的状态时你会以相反的顺序应用它们。
要了解有关各种集合的某些操作的时间复杂性的更多信息,您应该看一下 - http://docs.scala-lang.org/overviews/collections/performance-characteristics.html
请记住,它上面的“效率”没有任何意义。你应该总是问 - “效率......但做什么?”