【发布时间】:2014-02-13 03:43:22
【问题描述】:
我正在为我的网络应用程序中的操作构建一个框架。基本思想是它离线工作,所以我需要一种方法来传递发生的动作,然后可以倒带、合并、重放等等。 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] trait,它们相似,但 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],我就可以依靠它来实现可预测的行为.
干杯。
【问题讨论】:
标签: scala collections types type-parameter