我正在为我的web应用程序中的操作构建一个框架。基本思想是它可以离线工作,所以我需要一种方式来传递发生的操作,然后可以重新合并,重播等等。 ActionMeta是启用此行为的类,并且表示单个操作,类型S是操作的主题类型。以下是构成它的实际参数。斯卡拉,将值传递给任何集合
case class ActionMeta[S](
val timestamp: Instant,
val syncKey: SyncKey,
val action: Action[S],
val subjectId: UUID,
val subjectClientId: UUID,
val originMeta: JsValue,
val actionArgs: JsValue,
val status: ActionStatus,
val syncStatus: ActionSyncStatus,
val subActions: List[(Option[Any], ActionMeta[Any])]
) {
}
这和它的行为工作,我的规格为单行动和具有相同主题的动作堆栈,但现在我需要解决的最后一行,也就是子行动。关键问题是子行动往往会涉及不同的主题。操作本身被继承的对象从这些性状:
trait Action[S] {
val registryKey: String
ActionRegistry.register(registryKey, this)
def getSubjectIds(subject: S): (UUID, UUID)
def pullOriginMeta(subject: S): JsValue
def getSubjectRepresentation(id: UUID, clientId: UUID): S
def saveSubjectRepresentation(subject: S): S
def merge(args: JsValue, newArgs: JsValue): Option[JsValue]
def deleteSubjectRepresentation(id: UUID, clientId: UUID): Boolean
}
trait CreationAction[S] extends Action[S] {
def apply(actionArgs: JsValue = JsNull): (S, ActionMeta[S]) = {
val (res, updatedActionArgs) = this.forwards(actionArgs)
val (sid, scid) = this.getSubjectIds(res)
val actionMeta = new ActionMeta[S](
DateTime.now.toInstant, new SyncKey(), this, sid, scid,
JsNull, updatedActionArgs, Done, LocalAction, this.runSubActions(actionArgs)
)
(res, actionMeta)
}
def forwards(args: JsValue): (S, JsValue)
def backwards(subject: S, args: JsValue): JsValue
def runSubActions(forwardArgs: JsValue): List[(Option[Any], ActionMeta[Any])] = {
List()
}
}
也有TransformAction [S]和DeletionAction [S]的性状,这是类似的,但具有不同类型的签名forwards
/backwards
,并为不同的逻辑apply
。
object TestSideActionCreate extends {val registryKey = "actions:testSideCreate"}
with TestSideActionBase with CreationAction[TestSide] {
// omitted method bodies, not necessary to problem
def forwards(args: JsValue): (TestSide, JsValue) = ???
def backwards(subject: TestSide, args: JsValue): JsValue = ???
def merge(args: JsValue, newArgs: JsValue): Option[JsValue] = ???
override def runSubActions(args: JsValue): List[(Option[Any], ActionMeta[Any])] = {
List(
TestActionCreate(
Json.obj("id" -> UUID.randomUUID.toString)
).asInstanceOf[(Option[Any], ActionMeta[Any])]
)
}
}
基本上我的问题是,runSubActions
因为它是笨重的。这个方法可以工作,我可以像我期望的那样使用完整的类型来访问生成的子动作,但是,这仍然是我要做的很多我的最终实现,我的API,所以我不想如果我可以帮助它,则迫使编译器通过使用asInstanceOf来通过一系列不同类型的子动作。
有没有更好的方式来表达这种类型系统?我需要能够接受List[Option[Any], ActionMeta[Any]]
中的任何内容,因为我不想把我的双手绑在一起:只要它实现了ActionMeta[S]
并具有相应的Action[S]
,我可以依靠它来表现可预测性。
干杯。
包装听起来更符合我想要做的事情。想想在继续之前,我会再想一想如何去做。 – MalucoMarinero