在Kotlin中实现访问者模式的最佳方式

在Kotlin中实现访问者模式是否有任何窍门或常见方法? 任何可能对初学者都不明显的东西,但会导致更简洁或有组织的代码。

编辑澄清:我有一个AST的许多(~30)类型的节点。 目前,每个类都实现了自己的print()方法,我想把它分解到一个单独的Printer类中。 随着访问者模式的到位,将会更加清晰,增加其他的AST遍历类,其中会有几个。

阅读Java 8的这个答案 ,它所说的一切也适用于Kotlin:

对Java语言的补充不会使每个旧概念都过时。 实际上,Visitor模式非常适合支持添加新的操作。

Kotlin也是这样。 像Java 8一样,它具有Lambdas , SAM转换和允许默认实现的接口 。

一个变化是,如果你正在做类实例类型检查,而不是每个instanceof检查使用一个大的if语句,请使用Kotlin中的when表达式 :

在同一个Stackoverflow页面的不同答案中,它谈到了正在使用的Lambda,并在Java中显示了if语句决定调用哪个lambda。 而不是他们的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()); } 

使用这Kotlin:

 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中使用密封类来表示层次结构中的可能选项,然后编译器可以确定是否用尽了所有的情况,这意味着在when语句中不需要else

否则,该页面上的内容是真实的,对同一个问题的其他常见答案是Kotlin的好消息。 我不认为在Java 8,Scala或Kotlin中看到实际的字面访问者模式的情况并不常见,而是使用lambdas和/或模式匹配的一些变化。

其他相关文章:

  • 访问者模式与Java 8默认方法 (Kotlin也有)
  • 访问者模式与Java 8中的lambda抽象 (Kotlin也有lambda)
  • 访客模式Java 8 Lambda实现 (Kotlin也有lambda,记得使用when而不是large if

同伴对象和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###