Есть ли какие-либо варианты использования Шаблон посетителей в Scala?
Должен ли я использовать Match Matching в Scala каждый раз, когда я использовал шаблон посетителя в Java?
Есть ли какие-либо варианты использования Шаблон посетителей в Scala?
Должен ли я использовать Match Matching в Scala каждый раз, когда я использовал шаблон посетителя в Java?
Да, вы должны начать с сопоставления с образцом вместо шаблона посетителя. См. Интервью с Мартином Одерским (мой акцент):
Итак, правильный инструмент для работы действительно зависит от того, в каком направлении вы хочу расширить. Если вы хотите расширить с помощью новых данных, классический объектно-ориентированный подход с виртуальными методами. Если ты хочешь чтобы данные фиксировались и расширялись с новыми операциями, затем шаблоны гораздо лучше подходят. На самом деле шаблон дизайна - не путают с сопоставлением с образцом в объектно-ориентированном программировании, называемом шаблон посетителя, который может представлять некоторые из вещей, которые мы делаем с сопоставление шаблонов объектно-ориентированным способом на основе виртуального метода отправка. Но в практическом использовании шаблон посетителя очень громоздкий. Вы не могут делать многие вещи, которые очень легко сочетаются с сопоставлением с образцом. У вас очень тяжелые гости. И также оказывается, что с современная технология VM она более эффективна, чем сопоставление моделей. По обоим причинам я считаю, что для соответствия.
EDIT: Я думаю, что это требует немного лучшего объяснения и примера. Шаблон посетителя часто используется для посещения каждого node в дереве или подобном, например, абстрактном синтаксическом дереве (AST). Используя пример из превосходного Scalariform. Скалярные форматы scala с помощью парсинга scala, а затем прохождения AST, записывая его. Один из предоставленных методов принимает 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 (Checkstyle для Scala) мы используем модифицированную форму этого метода, но с тонким изменением. Нам нужно пересечь дерево, но каждая проверка касается только определенных узлов. Например, для EqualsHashCodeChecker он заботится только о методах равных и хэш-кодов. Мы используем следующий метод:
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(), которое происходит автоматически, если вы используете классы case.
Существует хороший обзор этого вопроса в документе Соответствие объектов с шаблонами Бураком Эмиром, Мартином Одерским и Джоном Уильямсом