在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
而不是largeif
)
同伴对象和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###