Используйте класс из списка универсального интерфейса - PullRequest
0 голосов
/ 22 мая 2018

Я пытаюсь реализовать QueryBus.По сути, я хочу зарегистрировать список QueryHandler s.Каждый QueryHandler реализует метод handle, определенный интерфейсом.Каждый QueryHandler связан с Query.Я хочу иметь возможность получить QueryHandler, используя Query и вызвать handle.

Дело в том, что дескриптор должен быть универсальным, потому что каждый QueryHandler обрабатывает Query по-своему,Все они берут выделенный Query и могут вернуть все, что захотят.

interface Query<R>

interface QueryHandler<R, Q : Query<R>> {
    fun handle(query: Q): R
    fun listenTo(): String
}

// DTOs
data class BookDto(val name: String)

// List books query
data class ListBooksQuery(val page: Int = 1): Query<List<BookDto>>

class ListBooksQueryHandler: QueryHandler<List<BookDto>, ListBooksQuery> {
    override fun handle(query: ListBooksQuery): List<BookDto> {
        return listOf(BookDto("Dune"), BookDto("Dune II"))
    }

    override fun listenTo(): String = ListBooksQuery::class.toString()
}

// Get book query
data class GetBookQuery(val name: String): Query<BookDto?>

class GetBookQueryHandler: QueryHandler<BookDto?, GetBookQuery> {
    override fun handle(query: GetBookQuery): BookDto {
        return BookDto("Dune")
    }

    override fun listenTo(): String = GetBookQuery::class.toString()
}

// Run it!

fun main(args: Array<String>) {
    // Initializing query bus
    val queryHandlers = mapOf(
        with(ListBooksQueryHandler()) {this.listenTo() to this},
        with(GetBookQueryHandler()) {this.listenTo() to this}
    )

    val command = ListBooksQuery()
    val result = queryHandlers[command::class.toString()].handle(command)

    // Should print the list of BookDto
    print(result)
}

Я даже не знаю, возможно ли это, если честно.

ОБНОВЛЕНИЕ 1: Я изменил пример использования в основном, чтобы показать, что я действительно пытаюсь сделать.List был для (плохой?) Демонстрационной цели.Я хочу сохранить QueryHandler s и получить их с карты.

Дополнительные ресурсы:

Вот что я действительно хочу сделать: https://gist.github.com/ValentinTrinque/76b7a32221884a46e657090b9ee60193

1 Ответ

0 голосов
/ 22 мая 2018

ОБНОВЛЕНИЕ Я прочитал вашу суть и попытался найти решение, которое обеспечит чистый интерфейс для пользователя QueryBusMiddleware.Обратите внимание, что я использовал объекты вместо классов для реализаций QueryHandler, что мне показалось более естественным (поскольку для каждой реализации Query существует только одна возможная запись на карте).

interface Query<R>

interface QueryHandler<R, Q: Query<R>> {
    fun handle(query: Q): R
    fun listenTo(): String
}

// DTOs
data class BookDto(val name: String)

// List books query
data class ListBooksQuery(val page: Int = 1): Query<List<BookDto>>

object ListBooksQueryHandler: QueryHandler<List<BookDto>, ListBooksQuery> {
    override fun handle(query: ListBooksQuery): List<BookDto> {
        return listOf(BookDto("Dune"), BookDto("Dune II"))
    }
    override fun listenTo(): String = ListBooksQuery::class.toString()
}

// Get book query
data class GetBookQuery(val name: String): Query<BookDto?>

object GetBookQueryHandler: QueryHandler<BookDto?, GetBookQuery> {
    override fun handle(query: GetBookQuery): BookDto {
        return BookDto("Dune")
    }

    override fun listenTo(): String = GetBookQuery::class.toString()
}

// Run it!
fun main(args: Array<String>) {
    // Initializing query bus

    val queryHandlers = listOf(
            ListBooksQueryHandler,
            GetBookQueryHandler
    )

    val dispatcher: QueryBusMiddleware = QueryDispatcherMiddleware(queryHandlers)

    // Calling query bus
    val query = ListBooksQuery()

    // Result should be List<BookDto>
    val result = dispatcher.dispatch(query)

    print(result)
}

interface QueryBusMiddleware {
    fun <R, Q : Query<R>> dispatch(query: Q): R
}

class QueryDispatcherMiddleware constructor(handlers: List<QueryHandler<*, *>>) : QueryBusMiddleware {
    private val handlers = HashMap<String, QueryHandler<*, *>>()

    init {
        handlers.forEach { handler -> this.handlers[handler.listenTo()] = handler }
    }

    override fun <R, Q : Query<R>> dispatch(query: Q): R {
        val queryClass = query::class.toString()
        val handler = handlers[queryClass] ?: throw Exception("No handler listen to the query: $queryClass")
        return handler::class.members.find { it.name == "handle" }!!.call(handler, query) as R
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...