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

时间:2015-11-09 04:46:06

标签: design-patterns kotlin

在Kotlin中实施visitor pattern是否有任何技巧或常用方法?任何对初学者来说都不明显的东西,但会导致更简洁或有组织的代码。

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

4 个答案:

答案 0 :(得分:5)

阅读{8} for Java 8,它所说的一切也适用于Kotlin:

  

对Java语言的添加不会使每个旧概念过时。事实上,访客模式非常擅长支持添加新操作。

这适用于Kotlin。与Java 8一样,它有this answerLambdasSAM 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和/或模式匹配的一些变体。

其他相关文章:

答案 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
相关问题