if(script.isInstanceOf[MouseListener])
canvas.addMouseListener(script.asInstanceOf[MouseListener])
if(script.isInstanceOf[MouseMotionListener])
canvas.addMouseMotionListener(script.asInstanceOf[MouseMotionListener])
if(script.isInstanceOf[KeyListener])
canvas.addKeyListener(script.asInstanceOf[KeyListener])
if(script.isInstanceOf[PaintListener])
addPaint(script.asInstanceOf[PaintListener])
这感觉非常重复。有没有更好的方法来写它?
答案 0 :(得分:2)
正如Archeg所提到的,使用模式匹配已经好多了。但对于这种情况,您也可以考虑反思:
def addListeners(target: AnyRef, listener: AnyRef, listenerClasses: Class[_]*) = {
val targetClass = target.getClass
listenerClasses.foreach { clazz =>
if (clazz.isInstance(listener)) {
try {
val m = targetClass.getMethod("add" + clazz.getSimpleName, clazz)
m.invoke(target, listener)
} catch {
case e => // log exception
}
}
}
}
addListeners(canvas, script,
classOf[MouseListener], classOf[MouseMotionListener], classOf[KeyListener], ...)
或使用Class.getInterfaces.filter(_.getName.endsWith("Listener"))
来避免枚举侦听器接口(如果您还想处理从超类继承的接口,则需要一些额外的逻辑)。
答案 1 :(得分:0)
这可能比你开始的更多重复,但它没有任何强制转换,并且它将每个Listener特定代码片段放在适当的Listener特性中:
trait Listener {
protected def howToAddToCanvas: Seq[Function1[Canvas, Unit]] = Seq.empty
def addToCanvas(canvas: Canvas): Unit = howToAddToCanvas.forall(_(canvas))
}
trait MouseListener extends Listener {
override def howToAddToCanvas =
super.howToAddToCanvas ++ Seq(_.addMouseListener(this))
}
trait MouseMotionListener extends Listener {
override def howToAddToCanvas =
super.howToAddToCanvas ++ Seq(_.addMouseMotionListener(this))
}
. . .
trait Script extends Listener { . . . }
object ASpecificScript extends Script with MouseListener with KeyListener with . . .
. . .
trait Canvas {
addMouseListener(listener: MouseListener): Unit
addMouseMotionListener(listener: MouseMotionListener): Unit
. . .
}
这种方法的一个缺点是你必须记住每个Listener特性中 super 的技巧。如果您在一个特征中忘记了该特征,那么该特征将会影响而不是增加.howToAddToCanvas
早于extends <trait> with <trait> with <trait> with ...
列表中出现的每个特征的NSUserDefaults
。除此之外(非常糟糕!),这种方法使编译器确保始终在正确的位置传递适当类型的Listener。
N.B。我没有测试过这个。