在Kotlin中实施visitor pattern是否有任何技巧或常用方法?任何对初学者来说都不明显的东西,但会导致更简洁或有组织的代码。
编辑澄清:我有一个AST,其中有许多(~30)种类型的节点。目前,每个类都实现了自己的print()
方法,我想将其分解为单独的Printer类。有了访问者模式,添加其他AST遍历类会更加清晰,其中会有几个。
答案 0 :(得分:5)
阅读{8} for Java 8,它所说的一切也适用于Kotlin:
对Java语言的添加不会使每个旧概念过时。事实上,访客模式非常擅长支持添加新操作。
这适用于Kotlin。与Java 8一样,它有this answer,Lambdas和SAM conversions。
如果您正在进行类实例类型检查,而不是对每个instanceof
检查使用大if
语句,则可以使用Kotlin中的interfaces that allow default implementations:
在同一个Stackoverflow页面的不同答案中,它讨论了正在使用的Lambdas,并在Java中显示if (animal instanceof Cat) {
catAction.accept((Cat) animal);
} else if (animal instanceof Dog) {
dogAction.accept((Dog) animal);
} else if (animal instanceof Fish) {
fishAction.accept((Fish) animal);
} else if (animal instanceof Bird) {
birdAction.accept((Bird) animal);
} else {
throw new AssertionError(animal.getClass());
}
语句,决定调用哪个lambda。而不是他们的when
expression:
when (animal) {
is Cat -> catAction.accept(animal)
is Dog -> dogAction.accept(animal)
is Fish -> fishAction.accept(animal)
is Bird -> birdAction.accept(animal)
else -> throw AssertionError(animal.javaClass)
}
使用此Kotlin:
is
在Kotlin中,您不需要进行强制转换,因为当编译器看到else
检查实例类型时会自动生成Java sample。
同样在Kotlin中,您可以使用smart cast来表示层次结构中可能的选项,然后编译器可以确定您是否已用尽所有情况,这意味着您不需要{{1}中的when
声明。
否则该页面上的内容是正确的,同一问题的其他常见答案是Kotlin的良好信息。我不认为在Java 8,Scala或Kotlin中看到实际的文字访问者模式是常见的,而是使用lambdas和/或模式匹配的一些变体。
其他相关文章:
when
代替大if
)答案 1 :(得分:2)
这里是一个不执行双重调度,但确实实现了数据与作用在其上的代码之间的分离的实现。
使用when
表达式(详尽无遗)“手动”完成访问者的派发,该表达式所需的模板更少,因为无需在所有访问者中覆盖accept()
方法,并且多个{访问者中的{1}}个方法。
visit()
答案 2 :(得分:0)
伴侣对象和lambda的组合可用于实现动态访问,如下所示:
interface Visitable { fun visit()}
class FooOne(): Visitable {
val title1 = "111"
companion object { var visit: (FooOne)->Unit = {} }
override fun visit() { FooOne.visit(this) }
}
class FooTwo(): Visitable {
val title2 = "222"
companion object { var visit: (FooTwo)->Unit = {} }
override fun visit() { FooTwo.visit(this) }
}
/* assign visitor functionality based on types */
fun visitorStars() {
FooOne.visit = {println("In FooOne: ***${it.title1}***") }
FooTwo.visit = {println("In FooTwo: ***${it.title2}***") }
}
/* assign different visitor functionality */
fun visitorHashes() {
FooOne.visit = { println("In FooOne: ###${it.title1}###") }
FooTwo.visit = {println("In FooTwo: ###${it.title2}###") }
}
fun main(args: Array<String>) {
val foos = listOf<Visitable>(FooOne(), FooTwo())
visitorStars()
foos.forEach {it.visit()}
visitorHashes()
foos.forEach {it.visit()}
}
>>>
In FooOne: ***111***
In FooTwo: ***222***
In FooOne: ###111###
In FooTwo: ###222###
答案 3 :(得分:0)
为了解决这个问题,我会使用这样的东西:
interface Visitable {
fun accept(visitor: Visitor)
}
然后实现:
class House : Visitable {
override fun accept(visitor: Visitor) {
visitor.visit(this)
}
}
class Car : Visitable {
override fun accept(visitor: Visitor) {
visitor.visit(this)
}
}
访客本身:
interface Visitor {
fun visit(entity: Car)
fun visit(entity: House)
}
和实施:
class Printer : Visitor {
override fun visit(entity: Car) {
println("Im in A Car")
}
override fun visit(entity: House) {
println( "I'm in a House")
}
}
用法:
fun main(args: Array<String>) {
val list = listOf<Visitable>(House(), Car())
val printer = Printer()
list.map { it.accept(printer) }
}
输出:
I'm in a House
Im in A Car