Как я могу создать такой интерфейс для системы наблюдателей? - PullRequest
2 голосов
/ 06 апреля 2011
addListener[FooEvent] { e => println("Got a FooEvent") }
dispatchEvent(new FooEvent())

Это вообще возможно?Мне нужно было бы иметь возможность преобразовать параметр типа в методе addListener в строку и сохранить слушателей в карте (eventtype -> функция) или что-то еще.Тогда для dispatchEvent мне нужно будет определить тип строки для параметра, чтобы получить прослушиватели для этого события.

Я не уверен в реализации, но я действительно хотел бы использовать такой интерфейсвместо того, чтобы объявлять 2 метода для каждого типа события в наблюдаемом объекте.Есть идеи?

1 Ответ

4 голосов
/ 06 апреля 2011

Да, это возможно и довольно прямо.Однако вы должны помнить, что вам нужно держаться за ссылку на функцию, которую вы передаете, если вы хотите снова удалить ее из слушателей.Вы можете сделать что-то вроде этого:

import collection.mutable.ArrayBuffer

val listeners = ArrayBuffer[FooEvent => Unit]()

def addListener(f: FooEvent => Unit) = {
  listeners += f
  f
}

def removeListener(f: FooEvent => Unit): Unit = {
  listeners -= f
}

def dispatchEvent(e: FooEvent) = listeners.foreach(f => f(e))

addListener возвращает функцию, чтобы вы могли сохранить ее в val для последующего ее удаления:

val listener = foo.addListener { e => println(e) }
foo.dispatchEvent(FooEvent(3))
foo.removeListener(listener)

Если вы хотитечтобы предоставить тип события в качестве параметра типа, необходимо дополнительно принять неявный параметр Manifest или ClassManifest:

import collection.mutable.{ArrayBuffer, HashMap}

val listeners = HashMap[Class[Any],ArrayBuffer[Any]]()

def addListener[A](f: A => Unit)(implicit mf: ClassManifest[A]): A => Unit = {
  listeners.getOrElseUpdate(mf.erasure.asInstanceOf[Class[Any]], ArrayBuffer[Any]()) += f
  f
}

def dispatch[A](e: A)(implicit mf: ClassManifest[A]) =
  for {
    evListeners <- listeners.get(mf.erasure.asInstanceOf[Class[Any]])
    listener <- evListeners
  } listener.asInstanceOf[A => Unit] apply e
}

И использовать его:

addListener[FooEvent] { e => println(e.x) }
dispatch(FooEvent(3))
...