Skip to content

Instantly share code, notes, and snippets.

@jakzal
Last active March 25, 2020 10:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jakzal/554049e89791e859978916263ed52589 to your computer and use it in GitHub Desktop.
Save jakzal/554049e89791e859978916263ed52589 to your computer and use it in GitHub Desktop.
EventBus implementation in Kotlin
package pl.zalas.eventbus
interface EventBus<in E> {
fun publish(event: E)
}
package pl.zalas.eventbus
import kotlin.reflect.KClass
class SimpleEventBus<E : Any> : EventBus<E> {
private val subscribers = mutableMapOf<KClass<*>, List<Subscriber<*>>>()
override fun publish(event: E) {
subscribers.filter { it.key.isInstance(event) }
.flatMap { it.value }
.forEach {
@Suppress("UNCHECKED_CAST")
(it as Subscriber<E>)(event)
}
}
inline fun <reified T : E> register(subscriber: Subscriber<T>) {
register(T::class, subscriber)
}
fun <T : E> register(type: KClass<T>, subscriber: Subscriber<T>) {
val existing = subscribers.getOrDefault(type, emptyList())
subscribers[type] = existing + subscriber
}
}
package pl.zalas.eventbus
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import java.util.*
class SimpleEventBusTests {
interface TestEvent
data class FooEvent(val id: UUID = UUID.randomUUID(), val details: String = "foo") : TestEvent
data class BarEvent(val id: UUID = UUID.randomUUID(), val count: Int = 100) : TestEvent
class TestEventSubscriber(val tracker: EventTracker) : Subscriber<TestEvent> {
override fun invoke(event: TestEvent) {
tracker.register("test", event)
}
}
class FooEventSubscriber(val tracker: EventTracker) : Subscriber<FooEvent> {
override fun invoke(event: FooEvent) {
tracker.register("foo", event)
}
}
class BarEventSubscriber(val tracker: EventTracker) : Subscriber<BarEvent> {
override fun invoke(event: BarEvent) {
tracker.register("bar", event)
}
}
class EventTracker : HashMap<String, List<TestEvent>>() {
fun register(name: String, event: TestEvent) {
val existing = getOrDefault(name, emptyList())
put(name, existing + event)
}
}
@Test
fun `it calls the registered subscribers according to the event type`() {
val tracker = EventTracker()
val eventBus = SimpleEventBus<TestEvent>()
eventBus.register(TestEventSubscriber(tracker))
eventBus.register(FooEventSubscriber(tracker))
eventBus.register(BarEventSubscriber(tracker))
val foo = FooEvent()
val bar = BarEvent()
eventBus.publish(foo)
eventBus.publish(bar)
assertEquals(listOf(foo, bar), tracker["test"])
assertEquals(listOf(foo), tracker["foo"])
assertEquals(listOf(bar), tracker["bar"])
}
@Test
fun `it register multiple subscribers of the same type`() {
val tracker = EventTracker()
val eventBus = SimpleEventBus<TestEvent>()
eventBus.register(FooEventSubscriber(tracker))
eventBus.register(FooEventSubscriber(tracker))
eventBus.register(FooEventSubscriber(tracker))
val foo = FooEvent()
eventBus.publish(foo)
assertEquals(listOf(foo, foo, foo), tracker["foo"])
}
}
package pl.zalas.eventbus
interface Subscriber<in E>: (E) -> Unit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment