чистый kotlin способ реализации шаблона публикации-подписки, который осведомлен о типе - PullRequest
0 голосов
/ 15 июня 2019

Мне интересно, как я могу реализовать простой шаблон публикации-подписки в kotlin с такими API:

Channel.publish(event: T)
Channel.subscribe{ event: T -> Unit)

Мне важно знать тип, так что Channel будет доставлять только события типа T только подписчику типа (T)->Unit (а не другому типу (S)->Unit, который S is T равен false)

Вот моя реализация. Но две вещи меня беспокоят. Посмотрите:

import kotlin.reflect.KClass

object Channel {

    private val subscribers: MutableMap<KClass<*>, (Any) -> Unit> = mutableMapOf()

    inline fun <reified T> publish(event: T) {
        subscribers[T::class]?.invoke(event as Any)
    }

    inline fun <reified T> subscribe(noinline subscriber: (T) -> Unit) {
        subscribers[T::class] = subscriber as (Any) -> Unit
    }

}

data class Person(val name: String)

fun main() {
    Channel.subscribe { person: Person -> println("Hello ${person.name}") }
    Channel.publish(Person("John"))
}

Броски event as Any и subscriber as (Any) -> Unit кажутся мне глупыми. Как я могу избавиться от этого? Возможно ли в этой проблеме?

ОБНОВЛЕНИЕ № 1: Я нашел решение избавиться от event as Any

    inline fun <reified T : Any> publish(event: T) {
        subscribers[T::class]?.invoke(event)
    }

1 Ответ

1 голос
/ 16 июня 2019

Ваша реализация будет работать для очень наивного случая. Но, например, несколько подписчиков для одного и того же типа события не поддерживаются в коде выше. То же самое касается случая подписки на супертип события. (т.е. иерархии событий)

Если вы не строите это как упражнение, я предлагаю вам использовать существующую реализацию, такую ​​как Шина событий Guava . Он написан не на Kotlin, а на Java, но работает с Kotlin без сбоев.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...