Kotlin, generics y una function que puede no tener arguments

Intento genérico el estándar en torno a un patrón muy común, y Kotlin me trae tentadoramente cerca.

Construí una class que funciona como un administrador de escucha, de la siguiente manera:

class GenericListenerSupport <EventArgumentType, ListenerFunction: (EventArgumentType) -> Unit> { private val listeners = mutableListOf<ListenerFunction>() fun addListener(listener: ListenerFunction) { listeners.add(listener) } fun removeListener(listener: ListenerFunction) { listeners.remove(listener) } fun fireListeners(argument: EventArgumentType) { listeners.forEach { it.invoke(argument) } } } 

y puede ser usado de la siguiente manera:

 class ExampleWithArgument { private val listenerSupport = GenericListenerSupport<String, (String)->Unit>() fun exampleAdd() { listenerSupport.addListener({ value -> System.out.println("My string: "+value)}) } fun exampleFire() { listenerSupport.fireListeners("Hello") } } 

Hasta aquí todo bien. Pero, ¿y si el oyente no tiene arguments? O estirando aún más, múltiples parameters.

Puedo resolver esto:

 class ExampleWithNoArgument { private val listenerSupport = GenericListenerSupport<Nothing?, (Nothing?)->Unit>() fun exampleAdd() { listenerSupport.addListener({ System.out.println("I've got no argument")}) } fun exampleFiring() { listenerSupport.fireListeners(null) } } 

pero huele, y obviamente no sirve para múltiples parameters.

¿Hay una mejor manera de lograr esto? por ejemplo, algo que apoya este concepto:

 private val listenerSupport = GenericListenerSupport<???, (String, Double)->Unit>() 

Dado que su GenericListenerSupport declara un parámetro de tipo EventArgumentType y espera una instancia de él en fun fireListeners(argument: EventArgumentType) , dudo que pueda soportar múltiples arguments de una manera limpia. En cambio, sugeriría usar una class de datos (que no es tanto código adicional), como una forma limpia y segura para envolver varios valores:

 data class MyEvent(val id: String, val value: Double) private val listenerSupport = GenericListenerSupport<MyEvent, (MyEvent) -> Unit>() 

En cuanto a pasar ningún valor, también puede usar la Unit , el tipo que tiene exactamente un valor Unit :

 listenerSupport.fireListeners(Unit) 

El sistema de tipo y la resolución no le permitirán pasar ningún argumento donde se espere una sola, pero, como @Ruckus T-Boom sugirió, puede hacer una extensión para disparar oyentes sin ningún valor donde se espera la Unit :

 fun GenericListenerSupport<Unit>.fireListeners() = fireListeners(Unit) 

Un poco fuera de tema, pero creo que puede simplificar el tipo si no necesita types de funciones personalizadas y (EventArgumentType) -> Unit es suficiente:

 class GenericListenerSupport<EventArgumentType> { /* Just use `(EventArgumentType) -> Unit` inside. */ }