使用通用接口列表中的类

时间:2018-05-22 12:15:03

标签: kotlin

我正在尝试实现QueryBus。基本上,我想注册QueryHandler的列表。每个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: 我更改了main中的用法示例,以显示我真正想要做的事情。 List是(不好?)演示目的。我想存储QueryHandler并从地图中检索它们。

其他资源:

这是我真正想做的事情: https://gist.github.com/ValentinTrinque/76b7a32221884a46e657090b9ee60193

1 个答案:

答案 0 :(得分:1)

更新我已经阅读了您的要点并尝试提供一个解决方案,为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
    }
}