我会在我的域名中直接解释这一点,因为否则会让人感到困惑......
在MtG中,有可替换的事件,例如获得生命。我想在事件执行之前使用部分函数来进行替换。为此,每个事件都需要是案例类的实例。
//a replaceable event
trait Event { def execute(): Unit }
//an effect that replaces an event
type ReplacementEffect = PartialFunction[Event, Event]
//applies all effects to the event. If a replacement doesn't match, the
//event remains unchanged
def replace(event: Event, effects: ReplacementEffect*) =
effects.foldLeft(event) { case (event, effect) => effect.applyOrElse(event, identity[Event] _) }
def executeReplaced(event: Event) = replace(event, activeEffects: _*).execute()
//example: A player's life points
var _life = 20
//one instance of a replaceable event
case class GainLife(life: Int) extends Event {
def execute() = {
// ====== here goes the Interesting Game Logic
_life += life
}
}
def gainLife(life: Int) =
// ====== the place where Interesting Game Logic belongs logically
executeReplaced(GainLife(life))
//execution:
val double: ReplacementEffect = {
//gain twice as much life
case GainLife(x) => GainLife(x * 2)
}
//one effect is active
val activeEffects = List(double)
//gain six life
println(_life)
gainLife(3)
println(_life)
如果我没有替换要求,我可以将(部分)压缩到以下内容:
//a replaceable event
type Event = () => Unit
//example: A player's life points
//one instance of a replaceable event
def gainLife(life: Int) = executeReplaced { () =>
_life += life
}
我更喜欢这段代码的是,有趣的游戏逻辑嵌套在它所属的gainLife方法中。 是否有可能在本地保留更多内容,即使我需要案例类?我能想到的最好的是这个,但除了看起来笨拙之外,GainLife
案例类是私有的块,所以它可以像没有案例类一样可用:
executeReplaced {
case class GainLife(life: Int) extends Event {
def execute() = {
_life += life
}
}
GainLife(life)
}
离开我的域名,问题基本上是让命令模式看起来很漂亮:命令的逻辑属于一个地方,我想在那里声明它。但是我必须在同一个地方定义命令的参数,并且我很难将它们提供给位于其他地方的代码。如果我将数据与逻辑分开,除了逻辑所在的位置之外,我无法在任何地方执行命令,并且它会再次破坏代码局部性。
答案 0 :(得分:0)
你可以使Event成为一个密封的特征,这意味着你只能在同一个文件中创建子类型,这样Scala编译器就会知道所有可能的子类型,并且你可以很好地在其他地方进行模式匹配(你仍然会得到紧密耦合)如果没有为某种类型的事件定义行为,则会出现编译错误。
sealed trait Event
case class GainLife(n: Int) extends Event
case class GainScore(n: Int) extends Event
然后在其他地方
var life, score = 5
event match {
case GainLife(n) => life += n
case GainScore(n) => score += n
}