Scala的event-sourced和CQRS案例代码

eligosource/eventsourced-example · GitHub

案例原理图:


个人目前观点:其领域模型的领域事件代码好像比较复杂,几乎是IF-ELSE这种条件判断模板,作者不能重构得好看一些吗?:


case class Invoice(
id: String,
items: List[InvoiceItem] = Nil,
discount: Option[BigDecimal] = None,
sentTo: Option[InvoiceAddress] = None) extends EventSourced[InvoiceEvent, Invoice] {

def addItem(item: InvoiceItem): Update[InvoiceEvent, Invoice] = ...
def setDiscount(discount: BigDecimal): Update[InvoiceEvent, Invoice] = ...
def sendTo(address: InvoiceAddress): Update[InvoiceEvent, Invoice] = ...

def handle(event: InvoiceEvent): Invoice = event match {
case InvoiceItemAdded(_, item) => copy(items = item :: items)
case InvoiceDiscountSet(_, discount) => copy(discount = Some(discount))
case InvoiceSent(_, to) => copy(sentTo = Some(to))
}
}

sealed trait InvoiceEvent extends Event { def invoiceId: String }
case class InvoiceItemAdded(invoiceId: String, item: InvoiceItem) extends InvoiceEvent
case class InvoiceDiscountSet(invoiceId: String, discount: BigDecimal) extends InvoiceEvent
case class InvoiceSent(invoiceId: String, to: InvoiceAddress) extends InvoiceEvent

在其Service中事件消费者部分代码:


def receive = {
case CreateInvoice(invoiceId) =>
process(createInvoice(invoiceId)) { invoice =>
emitter("listeners") sendEvent InvoiceCreated(invoiceId)
}
case AddInvoiceItem(invoiceId, expectedVersion, invoiceItem) =>
process(addInvoiceItem(invoiceId, expectedVersion, invoiceItem)) { invoice =>
emitter(
"listeners") sendEvent InvoiceItemAdded(invoiceId, invoiceItem)
}
case SetInvoiceDiscount(invoiceId, expectedVersion, discount) =>
process(setInvoiceDiscount(invoiceId, expectedVersion, discount)) { invoice =>
emitter(
"listeners") sendEvent InvoiceDiscountSet(invoiceId, discount)
}
case SendInvoiceTo(invoiceId, expectedVersion, to) =>
process(sendInvoiceTo(invoiceId, expectedVersion, to)) { invoice =>
emitter(
"listeners") sendEvent InvoiceSent(invoiceId, invoice, to)
}
case InvoicePaymentReceived(invoiceId, amount) =>
process(payInvoice(invoiceId, None, amount)) { invoice =>
emitter(
"listeners") sendEvent InvoicePaid(invoiceId)
}
}


Scala的Eventsourced库包使用介绍
[该贴被banq于2012-10-29 10:30修改过]

Scala这个案例代码也符合类似我们在事件、契约设计与BDD讨论的下图:

具体文章可翻墙看:
Building an Event-Sourced Web Application - Part 1: Domain Model, Events and State

事件更改的状态是Invoice这个聚合根中状态:


val overallUpdate: Update[InvoiceEvent, Invoice] = for {
updated1 <- invoice.addItem(InvoiceItem("x", 1, 10))
updated2 <- updated1.addItem(InvoiceItem(
"y", 2, 12))
updated3 <- updated2.sendTo(InvoiceAddress(
"foo", "bar", "baz"))
} yield updated3

[该贴被banq于2012-10-29 10:41修改过]

在看akka2.0的文档时,看过此人的博客,觉得很是复杂。