gpt4 book ai didi

scala - 以无状态方式处理输入事件

转载 作者:行者123 更新时间:2023-12-04 09:59:15 24 4
gpt4 key购买 nike

昨天我问我如何以功能方式处理键盘输入(使用 ScalaFX)。感谢@alfilercio 的帮助,我想出了这样的事情:

class InputHandler {
private val goUp: Int => State => State = step => state => State(state.x, state.y - step)
private val goDown: Int => State => State = step => state => State(state.x, state.y + step)
private val goLeft: Int => State => State = step => state => State(state.x - step, state.y)
private val goRight: Int => State => State = step => state => State(state.x + step, state.y)
private val doNothing: Int => State => State = step => state => state

private var behaviour: Int => State => State = doNothing

def keyPressedHandler(key: KeyEvent): Unit = {
behaviour = key.getCode match {
case KeyCode.Up.delegate => goUp
case KeyCode.Down.delegate => goDown
case KeyCode.Left.delegate => goLeft
case KeyCode.Right.delegate => goRight
case _ => doNothing
}
}

def keyReleasedHandler(key: KeyEvent): Unit = behaviour = doNothing

def update: Int => State => State = behaviour
}

然后有一个更新程序(工作名称),它根据耗时、一些内部逻辑和/或用户输入更新状态:
def update(state: State)(implicit inputHandler: InputHandler): State = { ... }
使用这种方法,核心类可以保持纯净,不需要单个变量。但是 InputHandler 本身仍然存在问题。我的意思是行为变量使它成为有状态的。这个 InputHandler 为用于生成 GUI 的 ScalaFX 添加了一种抽象。方法 keyPressedHandler/keyRelasedHandler 分别设置为 ScalaFX 场景事件处理程序。总而言之,我正在寻找从这个 InputHandler 中删除状态变量(行为)的方法。出于教育原因,我试图掌握函数式方法,这就是为什么我一直在用这个案例来打扰你:)

最佳答案

我个人认为所有 Listener s 和 Handler根据定义,s 是来自我们纯净世界之外的不纯净对象,因此 如果我想保持纯洁 ,我会让他们通过一些 IO 将命令作为值发送。

class SthListener(keyPressed: KeyCode => Unit,
keyReleased: KeyCode => Unit,
updateState: (State => Unit) => Unit) externds XListener {

def keyPressedHandler(key: KeyEvent): Unit = keyPressed(key.getCode)

def keyReleasedHandler(key: KeyEvent): Unit = keyReleased()

def update: Unit = updateState { state => // received from outside world
// how to update current component basing on received state
}
}

和其他地方
sealed trait Event
object Event {
case class KeyPressed(keyCode: Int) extends Event
case class KeyReleased(keyCode: Int) extends Event
}

val eventBus = Queue[Task, Event]

val stateRef = Ref[Task, State]

// translate pure operations on boundary of dirtyness
new SthListener(
keyPressed = keyCode => eventBus.enqueue1(Event.KeyPressed(keyCode)).runSync, // or runAndForget, or what works for you,
keyReleased = keyCode => eventBus.enqueue1(Event.KeyReleased(keyCode)).runSync,
update => stateRef.get.runSync
)

// handle state transitions
queue.dequeue
.evalMap {
case Event.KeyPressed(key) => stateRef.update(...)
case Event.KeyReleased(key) => stateRef.update(...)
}
.compile
.drain

总是这样做有意义吗?我个人不这么认为,但是您/您的团队在纯度、RT 方面看到了很多值(value),并且您有很多用例可以证明这种开销是合理的,然后您可以添加这种包装器以确保命令式 API 获胜不要强制你改变整个应用程序的编码风格,而只是在你强制使用命令式风格的部分。

如果这太过分了……好吧,您现在可以使用可变性和命令式风格,并在您感觉更熟悉后重新使用该方法。不要强制它,花点时间编写当前可以轻松理解和维护的代码。

关于scala - 以无状态方式处理输入事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61866016/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com