将抽象事件绑定到事件处理程序

时间:2017-05-25 10:59:08

标签: scala events types

修改:由于集合中类型的同质性,看起来我不想做的事情。

我希望以某种类型的状态机"以类型安全的方式引入eventshandlers

我的意思是&#34; typesafe&#34;是,而不是让每个处理程序在任意事件上进行模式匹配,如果它是一个感兴趣的事件,只做一些魔术,我想有一个像<的一样的共同点/ p>

val eventsAndHandlers = Map(
    StartEvent -> new StartHandler,
    EndEvent -> new EndHandler
  )

定义事件和处理程序之间的(当前1:1)映射。 (这可能会在将来发生变化,但此刻我很好奇为什么我在这里失败了)

到目前为止我所拥有的:

trait Event

abstract class EventHandler[E <: Event, R <: Any]
{
    def handle(event: E): R
}

case class StartEvent() extends Event
case class EntryEvent() extends Event

class StartHandler extends EventHandler[StartEvent, Unit]
{
    override def handle(event: StartEvent): Unit = println("StartHandler doing its work!")
}

class EndHandler extends EventHandler[EndEvent, Unit]
{
    override def handle(event: EndEvent): Unit = println("This is the end!")
}

在应用程序的某个地方我会有这个:

def main(): Unit = update(StartEvent())

def update(event: Event with Product with Serializable): Unit =
{
    eventsAndHandlers(event).handle(event) // This throws a compile time error
}

现在,这不会编译:

  

类型不匹配; found:test.Event with Product with Serializable required:scala.runtime.AbstractFunction0 [Product with Serializable with test.Event]

我想知道我错过了什么。

因此,我没有处理所有事件的处理程序,而是希望根据该映射只给出他感兴趣的事件。所以我想找到实际上能够处理给定事件的处理程序。

编辑:只是为了澄清我的意思&#34;处理每个事件&#34;

trait EventId

case class StartEventId() extends EventId
case class EndEventId() extends EventId

class Event(val id: EventId)

abstract class EventHandler[R <: Any]
{
  def handle(event: Event): R
}

在每个处理程序中然后是这些行:

override def handle(event: Event): Unit =
{
    event.id match
    {
        case x:EndEventId => println("The end is near!")
        case _ => println(s"Handler is not interested in that event")
    }
}

启动/更新状态机:

def main(): Unit = update(new Event(StartEventId()))

def update(event: Event): Unit =
{
    eventHandlers.map(
        h => h.handle(event)
    )
}

因此每个eventHandler都会获取每个事件并执行(或不执行)。

1 个答案:

答案 0 :(得分:1)

我认为你的地图会有问题,地图只有2种类型。对于所有Key,Map[Key,Value]他们的值是相同的类型。您尝试将键的子类型绑定到使用子类型的值。但编译器丢失了这些信息,它不知道它的子类型。您可以使用模式匹配再次选择它,但那可能会失败。

你可能需要用这样的东西来注释你的地图,但我认为你仍然会遇到麻烦。

Map[Event, EventHandler[_,_]]

你可以尝试将你的组合放在一个列表中并过滤它们,但我认为你最终需要有一些代码来为每种类型的事件执行匹配和丢弃。这是你想要避免的。

我能想出的最简单的事情就是让你的句柄方法接受任何Event并丢弃它,如果它不是处理程序的具体类型。

class EndHandler extends EventHandler[EndEvent, Unit] {
  override def handle(event: Event): Unit = {
    event match {
      case e: EndEvent => println("This is the end!")
      case other => println("unsupported event type, something wrong in map")
    }
  }
}

或模式匹配

你可以做的另一件事是完全类型保存是将你的组合放在一个大模式匹配语句而不是集合数据类型。无论如何,您的处理程序可能不会动态更改。

def handle(e: Event): Unit = e match {
  case e: StartEvent => StartHandler.handle(e)
  case e: EndEvent => EndHandler.handle(e)
}