웹 응용 프로그램에서 작업에 대한 프레임 워크를 구축하고 있습니다. 기본 아이디어는 오프라인에서 작동한다는 것이므로 발생하는 동작을 전달하는 방법이 필요합니다. 그런 다음 되감기, 병합, 재생 등을 수행 할 수 있습니다. 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()
}
}
도 비슷하지만 forwards
/backwards
에 대해 서로 다른 유형의 서명이 TransformAction [S]와 DeletionAction [S] 특성, 그리고 다른 논리가있다 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