Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Design patterns 在Kotlin中实现访问者模式的最佳方法_Design Patterns_Kotlin - Fatal编程技术网

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

Design patterns 在Kotlin中实现访问者模式的最佳方法,design-patterns,kotlin,Design Patterns,Kotlin,在Kotlin中实现有什么技巧或常用方法吗?任何对初学者来说可能不明显,但会导致更简洁或更有组织的代码的东西 编辑以澄清:我有一个包含许多(~30)种节点的示例。目前,每个类都实现了自己的print()方法,我想将其分解为一个单独的打印机类。在visitor模式就绪后,添加其他AST遍历类将更加简洁,其中将有几个类。阅读Java 8,它所说的一切也适用于Kotlin: 对Java语言的添加并不会使所有旧概念都过时。事实上,访问者模式非常擅长支持添加新操作 科特林也是如此。就像Java8一样,它有

在Kotlin中实现有什么技巧或常用方法吗?任何对初学者来说可能不明显,但会导致更简洁或更有组织的代码的东西

编辑以澄清:我有一个包含许多(~30)种节点的示例。目前,每个类都实现了自己的
print()
方法,我想将其分解为一个单独的打印机类。在visitor模式就绪后,添加其他AST遍历类将更加简洁,其中将有几个类。

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

对Java语言的添加并不会使所有旧概念都过时。事实上,访问者模式非常擅长支持添加新操作

科特林也是如此。就像Java8一样,它有

一个变化是,如果您正在执行类实例类型检查,那么对于每个
实例of
检查,请使用in-Kotlin,而不是使用大型
if
语句:

在同一个Stackoverflow页面上的另一个答案中,它讨论了正在使用的lambda,并在Java中显示了决定调用哪个lambda的
if
语句。而不是他们的:

if(猫的动物实例){
接受((猫)动物);
}else if(狗的动物实例){
接受((狗)动物);
}else if(鱼的动物实例){
接受((鱼)动物);
}else if(鸟类的动物实例){
接受(鸟)动物;
}否则{
抛出新的断言错误(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来说是很好的信息。我认为在Java8、Scala或Kotlin中,实际的文本访问者模式并不常见,而是使用lambdas和/或模式匹配的一些变体

其他相关文章:

  • (科特林也有)
  • (科特林也有兰姆达斯)
  • (Kotlin也有lambda,记住在时使用
    ,而不是在
    时使用大的

可以使用伴生对象和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###
接口访问表{fun visit()}
类FooOne():可访问{
val title1=“111”
伴随对象{var visit:(FooOne)->Unit={}
重写趣味访问(){FooOne.visit(this)}
}
类FooTwo():可访问{
val title2=“222”
伴随对象{var visit:(FooTwo)->Unit={}
覆盖乐趣访问(){FooTwo.visit(this)}
}
/*根据类型分配访问者功能*/
有趣的探视明星(){
FooOne.visit={println(“在FooOne:**${it.title1}***”)中)
FooTwo.visit={println(“在FooTwo:**${it.title2}***”)中)
}
/*分配不同的访问者功能*/
趣味visitorHashes(){
FooOne.visit={println(“在FooOne中:{it.title1}}}
FooTwo.visit={println(“在FooTwo:it.title2}}}
}
趣味主线(args:Array){
val foos=listOf(FooOne(),FooTwo())
访客之星()
foos.forEach{it.visit()}
visitorHashes()
foos.forEach{it.visit()}
}
>>>
在FooOne中:**111***
在FooTwo中:**222***
在FooOne中:###111###
在FooTwo中:####222###

这是一个实现,它不执行双重分派,但实现了数据和作用于数据的代码之间的分离

访问者的分派是“手动”完成的,使用
when
表达式(这是详尽的),它需要更少的锅炉板,因为不需要覆盖所有访问者中的
accept()
方法和访问者中的多个
visit()
方法

package visitor.addition
import visitor.addition.Expression.*

interface Visitor {
    fun visit(expression: Expression)
}

sealed class Expression {
    fun accept(visitor: Visitor) = visitor.visit(this)

    class Num(val value: Int) : Expression()
    class Sum(val left: Expression, val right: Expression) : Expression()
    class Mul(val left: Expression, val right: Expression) : Expression()
}

class PrintVisitor() : Visitor {
    val sb = StringBuilder()

    override fun visit(e: Expression) {
        val x = when (e) {
            is Num -> sb.append(e.value)
            is Sum -> stringify("+", e.left, e.right)
            is Mul -> stringify("*", e.left, e.right)
        }
    }

    fun stringify(name : String, left: Expression, right: Expression) {
        sb.append('(')
        left.accept(this); sb.append(name); right.accept(this)
        sb.append(')')
    }

}

fun main(args: Array<String>) {
    val exp = Sum(Mul(Num(9), Num(10)), Sum(Num(1), Num(2)))
    val visitor = PrintVisitor()
    exp.accept(visitor)

    println(visitor.sb) // prints: ((9*10)+(1+2))
}
package visitor.addition
导入visitor.addition.Expression*
界面访问者{
趣味之旅(表达:表达)
}
密封类表达式{
乐趣接受(访客:访客)=访客。访问(本)
类Num(val值:Int):表达式()
类和(左值:表达式,右值:表达式):表达式()
类Mul(val left:Expression,val right:Expression):Expression()
}
类PrintVisitor():Visitor{
val sb=StringBuilder()
覆盖趣味访问(e:表达式){
val x=何时(e){
is Num->sb.append(即值)
is Sum->stringify(“+”,e.左,e.右)
是Mul->stringify(“*”,e.左,e.右)
}
}
趣味字符串化(名称:字符串,左:表达式,右:表达式){
某人附加(“(”)
左.接受(这个);某人附加(名字);右.接受(这个)
某人附加(“)”)
}
}
趣味主线(args:Array){
val exp=Sum(Mul(Num(9),Num(10)),Sum(Num(1),Num(2)))
val visitor=PrintVisitor()
exp.accept(访客)
println(visitor.sb)//prints:((9*10)+(1+2))
}

要解决此问题,我将使用以下方法:

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) }
}


您是否要求有人代表您为Kotlin编写一个示例访问者模式?这个问题是广泛的、开放式的,很可能应该标记为结束。不,我只是问如何在我仍在学习的语言中惯用地实现特定模式——仅此而已。发布您对它的最佳猜测,让我们帮助您调整它。可能您只是将lambda传递给要遍历的节点,并在访问节点时回调lambda。从这里开始,发布代码,然后我们就可以从那里得到帮助。好的,我采用了一种通用的方法来回答你的问题,因为我不知道你的类层次结构以及会出现哪些问题。请参见下文。使用大屏幕
I'm in a House
Im in A Car