我在高中学习了 Java 和 Python,并且对 Python 非常熟悉。我最近开始学习kotlin,主要是为了好玩(定义函数的关键字是fun
,所以它必须是一种有趣的语言,对吧),但我有一个小问题。
假设我有一个国际象棋类的层次结构:
abstract class Piece {
...
}
class Rook : Piece() {
...
}
class Bishop : Piece() {
...
}
.
.
.
我正在接受用户的输入来生成板,所以如果用户输入 r
,我需要创建一个 Rook
对象,如果他输入 b
,我需要创建 Bishop
等
在python中,我可能会使用字典将输入字符串映射到相应的类,这样我就可以创建一个正确类型的对象:
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中使用反射,是否有效?
我想知道如何解决这个问题,我接受多个答案和我没有想出的其他解决方案。提前致谢。
答案 0 :(得分:3)
这无需反思即可完成。
您可以将输入字符映射到构造函数:
val pieceConstructorsByKeyChar = mapOf(
'r' to ::Rook,
'b' to ::Bishop,
// etc.
)
从地图中获取值会为您提供可为空值,因为您提供的键可能不在地图中。也许这很好,如果当您使用它时,您可能会传递玩家输入的可能不受支持的字符。然后你可能会通过告诉玩家再试一次来处理 null
:
val piece: Piece? = pieceConstructorsByKeyChar[keyPressed]?.invoke()
或者,如果您在已经检查它是有效击键之后进行查找,则可以安全地使用 !!
:
val piece: Piece = pieceConstructorsByKeyChar[keyPressed]!!()
答案 1 :(得分:0)
是的,您可以在 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
函数创建您想要的实例。如果您的输入映射不包含您提供的键,则它将返回 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")