Visitor Pattern을 스칼라에서 사용하는 유스 케이스가 있습니까?스칼라의 방문자 패턴
Java에서 방문자 패턴을 사용할 때마다 Scala에서 Pattern Matching을 사용해야합니까?
Visitor Pattern을 스칼라에서 사용하는 유스 케이스가 있습니까?스칼라의 방문자 패턴
Java에서 방문자 패턴을 사용할 때마다 Scala에서 Pattern Matching을 사용해야합니까?
예. 방문자 패턴 대신 패턴 일치로 시작해야합니다. 이 interview with Martin Odersky (내 강조)를 참조하십시오 :
그래서 작업에 적합한 도구가 정말 확장 할 하는 방향에 따라 달라집니다. 새로운 데이터로 확장하려면 가상 메소드로 고전적인 객체 지향 접근 방식 인 을 선택하십시오. 에 데이터를 고정시키고 새 작업으로 확장하려면 패턴 이 훨씬 적합합니다. 실제로 디자인 패턴이 있습니다 - 은 패턴 일치와 혼동되지 않습니다. 이라는 객체 지향 프로그래밍에서 방문자 패턴은 패턴 일치가있는 가상 메쏘드를 기반으로합니다. 발송. 그러나 실제 사용시 방문자 패턴은 매우 부피가 커집니다. 은 패턴 일치가 매우 쉬운 많은 작업을 수행 할 수 없습니다. 당신은 매우 무거운 방문자로 끝납니다. 또한 현대의 VM 기술 을 사용하면 패턴 일치보다 비효율적입니다. 이러한 두 가지 이유 때문에 패턴 과 일치하는 역할이 분명하다고 생각합니다.
편집 : 이것은 좀 더 나은 설명과 예제가 필요하다고 생각합니다. 방문자 패턴은 종종 AST (Abstract Syntax Tree)와 같이 트리 또는 유사 사이트의 모든 노드를 방문하는 데 사용됩니다. 우수한 Scalariform의 예를 사용하십시오. Scalariform은 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
이 잘 자바 방문자 패턴으로 수행 할 수 있지만, 훨씬 더 간결 스칼라에서 패턴 매칭 수행 할 수있는 작업입니다. 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()
}
공지 사항 우리는 반복적으로, visit()
을 visitfn()
을하지 호출하고 있습니다. 이렇게하면 코드를 복제하지 않고이 메소드를 재사용하여 트리를 탐색 할 수 있습니다. 우리 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()
을 정의하는 것 외에 이동중인 데이터 구조를 수정할 필요가 없습니다.
니스 호출 할 수 있습니다. 이것은 특정 '액션'코드에서 방문 기능을 분리하여 스칼라에서 방문자 패턴을 찾을 수 있었던 최고의 예제 코드입니다. – Core
"방문자 패턴은 종종 나무 나 그와 유사한 노드의 모든 노드를 방문하는 데 사용됩니다."- IMHO 이는 일반적인 오해입니다. 방문자 패턴은 이름에도 불구하고 여러 노드를 방문하는 것과 아무런 관련이 없습니다. GoF의 원래 의도는 컴파일러가 선언 된 모든 하위 유형을 정확하게 처리하도록 요구할 때 엄격한 ADT 의미를 갖는 것입니다. 이것은 부속 유형의 닫힌 세트를 지정하며 비공식 부속 유형의 추가를 허용하지 않습니다. – beefeather
수백 개의 노드 유형이 있고 각기 다른 코드로 방문해야 할 때 어떻게됩니까? –
는 부락 국왕, 마틴 오더 스키, 존 윌리엄스 종이 Matching Objects with Patterns에서 그 질문의 좋은 설문 조사가
당신이 implicits 객체/방법 방문자 패턴 아마도 ... – aishwarya