仕様に特に悩まないものでかつ色んな機能を使えるもの=状態管理!
そういえばScalaの練習も状態管理だったなぁ〜
ということで、書いてみた(感想は後ほど)
実際には全体を3回ほど見直して記述を試してみた結果の最後の形(色々試すのに飽きたの意味)
sealed class Node<T>(val name: String) {
class ActionNode<T>(name: String , val action: (T) -> Unit) : Node<T>(name)
class StateNode<T>(name: String) : Node<T>(name)
}
data class NodeLink<T>(val fromNode: Node<T> , val toNode: Node<T> , val check : (T?) -> Boolean)
data class Flow<T>(val getState : (T) -> String , val setState : (T,String) -> T , val nodes : Map<String,Node<T>> , val links : Map<String,Map<String,NodeLink<T>>> )
fun <T> Flow<T>.plus(node : Node<T>) : Flow<T> {
return this.copy(nodes = this.nodes + Pair(node.name , node))
}
fun <T> Flow<T>.link(from: String, toName: String, check: (T?) -> Boolean) : Flow<T>? {
val fromNode = nodes.get(from) ?: return null
val toNode = nodes.get(toName) ?: return null
return link(fromNode, toNode, check);
}
fun <T> Flow<T>.link(fromNode: Node<T>, toNode: Node<T>, check: (T?) -> Boolean) : Flow<T> {
val nodeLink = NodeLink<T>(fromNode,toNode,check)
val child = links.get(fromNode.name) ?: mutableMapOf<String,NodeLink<T>>()
val newChild = child + Pair(toNode.name , nodeLink)
val newLinks = this.links + Pair(fromNode.name , newChild)
return this.copy(links = newLinks)
}
class ToNextStatusException(message: String?) : Exception(message)
class FlowExecutor<T> (val flow: Flow<T>) {
init {
// 本当はflowのチェック入れたかった
}
fun toNextStatus(data : T) : T {
val current = flow.getState(data)
val currentNode = flow.nodes.get(current) ?: throw ToNextStatusException("status name not found")
return walkNode(data, currentNode);
}
protected fun checkNode(data: T , toNode : Node<T>) :T =
when (toNode) {
is Node.ActionNode<T> -> {
toNode.action(data)
walkNode(data,toNode)
}
is Node.StateNode<T> -> flow.setState(data , toNode.name)
}
protected fun walkNode(data: T, currentNode : Node<T>) : T {
val nexts = flow.links.get(currentNode.name) ?: throw ToNextStatusException("status name not found")
val nextNodes = nexts.values.filter { it.check(data) }
return when (nextNodes.size) {
0 -> throw ToNextStatusException("zero match")
1 -> checkNode(data , nextNodes.first().toNode)
else -> throw ToNextStatusException("many match")
}
}
}判ったこと