Kotlin 责任链模式与泛型
Kotlin chain of responsibility pattern with generics
使用责任链模式 I 运行 解决了下一个链元素预期具有与第一个元素相同的通用类型的问题。我知道 为什么 会发生这种情况:第一个处理程序期望第二个处理程序使用通用类型 "Apple"。我只是不知道如何解决它。
有一个关于如何 handle it in java here 的答案,但由于 java 没有具体化的类型,所有这些方法在 Kotlin 中看起来应该有所不同,对吗?
我想到了不同的选择:
- 不要使用泛型 - 会导致将集合类型转换为特定的子类型并且看起来不干净
- 尝试使用具体化类型(如何?)
为了说明问题,我在下面发布了一个演示代码。
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!!
}
}
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
关于具体化类型参数:具体化类型参数仅适用于内联函数。不适用于 class.
上的类型参数
这在很大程度上取决于您希望处理程序如何交互的细节。对于此代码,只需将下一个处理程序的类型(在 var nextHandlerInChain
和 fun setNextHandler
中更改为 ChainHandler<*>
即可,因为 process()
returns 独立于 T
无论如何。
使用责任链模式 I 运行 解决了下一个链元素预期具有与第一个元素相同的通用类型的问题。我知道 为什么 会发生这种情况:第一个处理程序期望第二个处理程序使用通用类型 "Apple"。我只是不知道如何解决它。
有一个关于如何 handle it in java here 的答案,但由于 java 没有具体化的类型,所有这些方法在 Kotlin 中看起来应该有所不同,对吗?
我想到了不同的选择:
- 不要使用泛型 - 会导致将集合类型转换为特定的子类型并且看起来不干净
- 尝试使用具体化类型(如何?)
为了说明问题,我在下面发布了一个演示代码。
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!!
}
}
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
关于具体化类型参数:具体化类型参数仅适用于内联函数。不适用于 class.
上的类型参数这在很大程度上取决于您希望处理程序如何交互的细节。对于此代码,只需将下一个处理程序的类型(在 var nextHandlerInChain
和 fun setNextHandler
中更改为 ChainHandler<*>
即可,因为 process()
returns 独立于 T
无论如何。