代码之家  ›  专栏  ›  技术社区  ›  keyboardsamurai

具有泛型的Kotlin责任链模式

  •  2
  • keyboardsamurai  · 技术社区  · 6 年前

    有一个关于如何 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!!
        } 
    }
    
    2 回复  |  直到 6 年前
        1
  •  6
  •   marstran    6 年前

    科特林有一种叫做星体投影的东西,可能对你有帮助。它基本上告诉编译器,您并不真正关心 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
  •  2
  •   Alexey Romanov    6 年前

    var nextHandlerInChain fun setNextHandler ChainHandler<*> 会有用的,因为 process() T 不管怎样。