gpt4 book ai didi

design-patterns - Scala 中的访问者模式

转载 作者:行者123 更新时间:2023-12-03 01:18:37 27 4
gpt4 key购买 nike

是否有使用Visitor Pattern的用例在斯卡拉?

我应该使用 Pattern Matching每次我在 Java 中使用访问者模式时都会在 Scala 中吗?

最佳答案

是的,您可能应该从模式匹配而不是访问者模式开始。看这个interview with Martin Odersky (我的重点):

So the right tool for the job really depends on which direction you want to extend. If you want to extend with new data, you pick the classical object-oriented approach with virtual methods. If you want to keep the data fixed and extend with new operations, then patterns are a much better fit. There's actually a design pattern—not to be confused with pattern matching—in object-oriented programming called the visitor pattern, which can represent some of the things we do with pattern matching in an object-oriented way, based on virtual method dispatch. But in practical use the visitor pattern is very bulky. You can't do many of the things that are very easy with pattern matching. You end up with very heavy visitors. And it also turns out that with modern VM technology it's way more innefficient than pattern matching. For both of these reasons, I think there's a definite role for pattern matching.

编辑:我认为这需要一些更好的解释和一个例子。访问者模式通常用于访问树或类似树中的每个节点,例如抽象语法树(AST)。使用优秀的 Scalariform 中的示例。 Scalariform 通过解析 Scala 然后遍历 AST 并将其写出来来格式化 scala 代码。提供的方法之一采用 AST 并按顺序创建所有标记的简单列表。使用的方法是:

private def immediateAstNodes(n: Any): List[AstNode] = n match {
case a: AstNode ⇒ List(a)
case t: Token ⇒ Nil
case Some(x) ⇒ immediateAstNodes(x)
case xs @ (_ :: _) ⇒ xs flatMap { immediateAstNodes(_) }
case Left(x) ⇒ immediateAstNodes(x)
case Right(x) ⇒ immediateAstNodes(x)
case (l, r) ⇒ immediateAstNodes(l) ++ immediateAstNodes(r)
case (x, y, z) ⇒ immediateAstNodes(x) ++ immediateAstNodes(y) ++ immediateAstNodes(z)
case true | false | Nil | None ⇒ Nil
}

def immediateChildren: List[AstNode] = productIterator.toList flatten immediateAstNodes

这项工作完全可以通过 Java 中的访问者模式来完成,但通过 Scala 中的模式匹配可以更简洁地完成。在 Scalastyle (Scala 的 Checkstyle),我们使用此方法的修改形式,但有细微的变化。我们需要遍历这棵树,但每次检查只关心某些节点。例如,对于 EqualsHashCodeChecker ,它只关心定义的 equals 和 hashCode 方法。我们使用以下方法:

protected[scalariform] def visit[T](ast: Any, visitfn: (Any) => List[T]): List[T] = ast match {
case a: AstNode => visitfn(a.immediateChildren)
case t: Token => List()
case Some(x) => visitfn(x)
case xs @ (_ :: _) => xs flatMap { visitfn(_) }
case Left(x) => visitfn(x)
case Right(x) => visitfn(x)
case (l, r) => visitfn(l) ::: visitfn(r)
case (x, y, z) => visitfn(x) ::: visitfn(y) ::: visitfn(z)
case true | false | Nil | None => List()
}

请注意,我们递归调用 visitfn(),而不是 visit()。这允许我们重用这个方法来遍历树而无需重复代码。在我们的 EqualsHashCodeChecker 中,我们有:

private def localvisit(ast: Any): ListType = ast match {
case t: TmplDef => List(TmplClazz(Some(t.name.getText), Some(t.name.startIndex), localvisit(t.templateBodyOption)))
case t: FunDefOrDcl => List(FunDefOrDclClazz(method(t), Some(t.nameToken.startIndex), localvisit(t.localDef)))
case t: Any => visit(t, localvisit)
}

所以这里唯一的样板是模式匹配中的最后一行。在 Java 中,上述代码完全可以实现为访问者模式,但在 Scala 中,使用模式匹配更有意义。另请注意,除了定义 unapply() 之外,上面的代码不需要修改正在遍历的数据结构,如果您使用案例类,这会自动发生。

关于design-patterns - Scala 中的访问者模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8618082/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com