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