Вы не можете заставить его скомпилироваться по 3 различным причинам:
Поскольку handleExample
является методом экземпляра, вы не можете ссылаться на него в супер-конструкторе, так как экземпляр вашего подкласса еще не создано.
Если вы хотите ссылку на функцию метода экземпляра, вы должны поставить перед ней префикс ::
, так что в вашем случае ::handleExample
.
Функция handleExample
принимает событие типа ExampleEvent
, поэтому оно не соответствует типу ввода Event
, в этом случае вам понадобится приведение.
Тем не менее, есть решение вашей проблемы, которое решает 3 пункта выше и бремя повторять этот шаблон для каждого EventHandler
подкласса.
Объяснение все на комментарии.
inline fun <reified T : Event> typedCoroutine(crossinline block: suspend (T) -> Unit): Pair<KClass<out Event>, suspend (Event) -> Unit> =
// Since the type is reified, we can access its class.
// The suspend function calls the required suspend function casting its input.
// The pair between the two is returned.
T::class to { event -> block(event as T) }
abstract class EventHandler {
// Require the subclasses to implement the handlers.
protected abstract val handlers: Map<KClass<out Event>, suspend (Event) -> Unit>
suspend fun handle(event: Event) {
val handler = handlers[event::class]
if (handler != null) {
handler(event)
} else {
throw IllegalStateException("No handler configured for $event")
}
}
}
class ExampleHandler : EventHandler() {
// The type of typedCoroutine is inferred from handleExample.
override val handlers: Map<KClass<out Event>, suspend (Event) -> Unit> = mapOf(typedCoroutine(::handleExample))
suspend fun handleExample(event: ExampleEvent) {
TODO()
}
}
Используя typedCoroutine
, вы можете легко заполнить карту handlers
во всех ваших подклассах EventHandler
.