我在高中学过java和python,我对python非常熟悉。我最近开始学习kotlin,主要是为了好玩(定义函数的关键字是fun
,所以它必须是一种有趣的语言,对吧),但是我有一个小问题。
让我们假设我有一个棋子类的层次结构:
abstract class Piece {
...
}
class Rook : Piece() {
...
}
class Bishop : Piece() {
...
}
.
.
.
我从用户那里获取输入来生成电路板,所以如果用户输入r
,我需要创建一个Rook
对象,如果他输入b
,我需要创建一个Bishop
等等。
class Piece:
...
class Rook(Piece):
...
class Bishop(Piece):
...
.
.
.
input_map = {
'r': Rook,
'b': Bishop,
...
}
s = input_map[input()]() # use user input as key and create a piece of the correct type
当我发现这个模式时,我真的很惊讶。在java中,我不得不使用一个switch case或一堆if else if
来实现相同的结果,这并不是世界末日,特别是如果我将其抽象为一个单独的函数,但它不如python方法好。
我想在kotlin中做同样的事情,我想知道kotlin是否有类似的模式,因为它是像python这样的现代语言(我知道,我知道,python不是新的,但我认为它非常现代)。我试着上网看看,但似乎我不能像在python中那样在变量或映射中存储类(类,而不是对象)。
我错了吗?我可以在kotlin中使用类似的模式吗?还是我必须回到when
语句(或表达式)?
如果我没有弄错的话,在java中使用反射可以实现类似的模式。我从来没有深入学习过java中的反射,但我知道这是一种动态使用类的方法,我可以在python中免费做到这一点。我还听说,在java中,反射应该作为最后的手段使用,因为它效率低下,被认为是"黑魔法"。如果你明白我的意思。这是否意味着我需要在kotlin中使用反射来实现该结果?如果是这样,是否建议在kotlin中使用反射,它是否有效?
我想知道如何解决这个问题,我接受多个答案和我没有想到的额外解决方案。提前谢谢。
无需反射。
可以将输入字符映射到构造函数:
val pieceConstructorsByKeyChar = mapOf(
'r' to ::Rook,
'b' to ::Bishop,
// etc.
)
从映射中获取值会给您一个空值,因为您提供的键可能不在映射中。也许这是好的,如果当你使用这个,你可能会传递一个角色,玩家键入可能不支持。然后你可能会通过告诉玩家再试一次来处理null
:
val piece: Piece? = pieceConstructorsByKeyChar[keyPressed]?.invoke()
或者,如果您在已经检查了它是一个有效的击键之后进行查找,则可以安全地使用!!
:
val piece: Piece = pieceConstructorsByKeyChar[keyPressed]!!()
是的,您可以在Kotlin中使用类似的方法。Kotlin有许多特性并支持反射。让我写一个关于你的问题的例子。
首先创建由用户输入生成的类。
abstract class Piece
class Rook : Piece()
class Bishop : Piece()
创建类映射
val inputMap = mapOf(
"r" to Rook::class.java,
"b" to Bishop::class.java
)
使用newInstance
函数创建您想要的实例。如果你输入的map不包含你给出的key,那么它将返回null
。
val rook = inputMap["r"]?.newInstance()
val bishop = inputMap["b"]?.newInstance()
// null
val king = inputMap["k"]?.newInstance()
还可以编写自定义扩展来创建新对象。
fun <T> Map<String, Class<out T>>.newInstance(key: String) = this[key]?.newInstance()
// Create an instance with extension function
inputMap.newInstance("r")