【问题标题】:Kotlin chain of responsibility pattern with generics带有泛型的 Kotlin 责任链模式
【发布时间】:2018-09-24 20:43:25
【问题描述】:

使用责任链模式时,我遇到了一个问题,即下一个链元素应该具有与第一个元素相同的泛型类型。我知道为什么会发生这种情况:第一个处理程序希望第二个处理程序使用通用类型“Apple”。我只是不知道如何解决它。

有一个关于如何handle it in java here 的答案,但是由于 java 没有具体类型,并且所有这些方法在 Kotlin 中看起来应该不同,对吧?

我想到了不同的选择:

  1. 不要使用泛型 - 会导致将集合类型转换为特定的子类型并且看起来不干净
  2. 尝试使用具体类型(如何?)

为了说明问题,我在下面发布了一个演示代码。


data class Apple(val name:String, val color:Int) 
data class Orange(val circumference:Double)

object Main{
    @JvmStatic
    fun main(args: Array<String>) {
        val first = FirstHandler()
        val second = SecondHandler()
        first.setNextHandler(second)  // !!! wrong type here since <Apple> is expected
        first.process()
    } 
}

abstract class ChainHandler<T>{
    protected var nextHandlerInChain:ChainHandler<T>? = null
    fun setNextHandler(handler: ChainHandler<T>): ChainHandler<T> {
        this.nextHandlerInChain = handler
        return handler
    }

    abstract fun peel(): Collection<T>
    abstract fun process():MutableMap<String,Any> }

class FirstHandler : ChainHandler<Apple>() {
    override fun peel(): Collection<Apple> {
        return Collections.emptyList<Apple>()
    }
    override fun process(): MutableMap<String, Any> {
        val peeledApples = peel()
        val map = nextHandlerInChain?.process()
        map?.put("apples",peeledApples) ?:kotlin.run {
            val map = mutableMapOf<String,Any>()
            map.put("apples",peeledApples)
        }
        return map!!
    } }

class SecondHandler : ChainHandler<Orange>() {
    override fun peel(): Collection<Orange> {
        return Collections.emptyList<Orange>()
    }
    override fun process(): MutableMap<String, Any> {
        val peeledOranges = peel()
        val map = nextHandlerInChain?.process()
        map?.put("oranges",peeledOranges) ?:kotlin.run {
            val map = mutableMapOf<String,Any>()
            map.put("oranges",peeledOranges)
        }
        return map!!
    } 
}

【问题讨论】:

    标签: design-patterns kotlin chain-of-responsibility


    【解决方案1】:

    Kotlin 有一种叫做星形投影的东西,它可能会在这方面对您有所帮助。它基本上告诉编译器你并不真正关心你得到什么类型的ChainHandler。您可以使用它来编译您的setNextHandler,如下所示:

    abstract class ChainHandler<T>{
      // Note the star projection here
      protected var nextHandlerInChain: ChainHandler<*>? = null
    
      // Defining a type parameter S, so that the return type is equal to the input type.
      fun <S> setNextHandler(handler: ChainHandler<S>): ChainHandler<S> {
        this.nextHandlerInChain = handler
        return handler
      }
    
      ...
    }
    

    您可以在此处阅读有关星形投影的更多信息:https://kotlinlang.org/docs/reference/generics.html#star-projections

    关于具体化类型参数:具体化类型参数仅适用于内联函数。不适用于类的类型参数。

    【讨论】:

      【解决方案2】:

      这在很大程度上取决于您希望处理程序如何交互的细节。对于此代码,只需将下一个处理程序的类型(在 var nextHandlerInChainfun setNextHandler 中更改为 ChainHandler&lt;*&gt; 即可,因为 process() 无论如何都会返回独立于 T 的内容。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-26
        • 1970-01-01
        • 2013-11-17
        • 1970-01-01
        • 1970-01-01
        • 2018-02-28
        相关资源
        最近更新 更多