Visitor Pattern

개념
‘데이터 구조’와 처리를 분리 한다. 데이터 구조 안을 돌아다니는 주체인 '방문자'를 나타내는 클래스를 준비해서 그 클래스에게 처리를 맡긴다. 랜더링, 이벤트처리, 탐색 등

 

I. Visitor Pattern

가. 의도

- 객체 구조에 속한 요소에 수행될 오퍼레이션을 정의하는 객체이다. Visitor 패턴은 처리되어야 하는 요소에 대한 클래스를 변경하지 않고 새로운 오퍼레이션을 정의할 수 있게 한다

- 오퍼레이션 들이 여러 노드 클래스에 걸쳐 분산되어 있어서 시스템의 이해 및 변경, 유지보수를 어렵게 만든다. 이때 각 클래스의 관련된 오퍼레이션을 모아 Visitor라는 별도의 클래스를 만들고 이를 추상 구문 트리의 원소 클래스를 알아낸다. 아규먼트로 원소를 포함한다.

 

나. 정의 

- ‘데이터 구조’와 처리를 분리

- 데이터 구조 안을 돌아다니는 주체인  '방문자'를 나타내는 클래스를 준비해서 그 클래스에게 처리를 맡김

- 랜더링, 이벤트처리, 탐색 등
    : 다양한 객체에 새로운 기능을 추가해야 하는데 캡슐화가 별로 중요하지 않은 경우에는 비지터 패턴을 사용한다.

 

다. 활용

- 객체 구조가 다른 인터페이스를 가진 클래스를 포함하고 있어서 구체적 클래스에 따라 오퍼레이션을 수행하고자 할 때

- 구별되고 관련되지 않은 많은 오퍼레이션이 객체에 수행될 필요가 있지만, 오퍼레이션으로 인해 클래스들을 복잡하게 하고 싶지 않을 때. Visitor 클래스는 하나의 클래스에 관련되지 않은 모든 오퍼레이션을 함께 정의함으로써 오퍼레이션을 유지시킨다. 객체의 구조가 많은 어플리케이션에 의해 공유될 때 Visitor 클래스를 사용해 필요한 애플리케이션에만 오퍼레이션을 둔다

 

라. 결과

- Visitor 클래스는 새로운 오퍼레이션을 쉽게 추가한다 – 방문자를 추가하면 객체 구조에 대한 새로운 오퍼레이션을 추가한 것이 된다

- 방문자를 통해 관련된 오퍼레이션을 하나로 모아 관련되지 않은 오퍼레이션과 분리할 수 있다

- 새로운 ConcreteElement 클래스를 추가하기는 어렵다 – 객체의 구조에 적용될 알고리즘의 변화가 자주 발생하거나 이같은 구조를 구성하는 객체 클래스에 변화가 자주 발생할 때 적용한다

- 클래스 계층 구조에 걸친 방문 – Iterator는 Item타입의 객체만을 관리할 수 있어 서로 다른 종류의 요소를 갖는 구조체를 탐색하지는 못한다. 그러나 Visitor 객체는 동일한 부모 클래스가 아니어도 객체 구조를 순회할 수 있다

- 상태를 누적할 수 있다 – 객체 구조 내의 각 원소를 방문할 때 상태를 누적할 수 있다

- 캡슐화 전략을 위배할 수 있다 – 요소의 내부 상태에 접근하는 데 필요한 오퍼레이션들을 모두 공개 인터페이스로 만들것을 강요하게 되므로

 

마. 적용시 제기되는 실행 문제

- 이중 디스패치- 사용자가 오퍼레이션을 변경하지 않고 클래스에 추가하게 되는데 이를 위해 이중 디스패치를 사용한다. 이중 디스패치는 실행된 오퍼레이션이 요청의 종류와 두 개의 수신자 유형에 따라 다르다는 것을 의미. Accept()는 이중 디스패치 오퍼레이션이다. 즉 visitor 유형과 element 유형에 따라 다르다. CLOS는 이중 디스패치를 직접 지원하고, C++이나 Smalltalk은 single dispatch를 지원한다

- 누가 객체 구조를 순회할 책임을 지는가?

 

바. 관련 패턴

- Visitor 패턴은 Composite 패턴이 정의하는 복합 객체 구조에 대한 오퍼레이션에 적용될 수 있다. 또 Interpreter 패턴의 해석 과정에도 사용할 수 있다

 

사. 참여객체

- Visitor: 각 ConcreteElement 클래스에 대한 Visit 오퍼레이션을 선언한다. 오퍼레이션의 이름과 인터페이스 형태는 Visit() 요청을 보내는 방문자에게 보내는 클래스를 명시한다. 이로써 방문자는 방문할 요소의 실제 서브클래스를 결정한다. 그리고 나서 방문자는 Element 가 제공하는 인터페이스를 통해 직접 Element 객체에 접근할 수 있다.

- ConcreteVisitor: Visitor 클래스에 정의된 오퍼레이션을 구현한다. 각 오퍼레이션은 객체에 해당하는 클래스에 정의된 알고리즘을 구현한다. ConcreteVisitor 클래스는 내부 상태를 저장하고 있으며, 알고리즘이 운영될 수 있는 상황 정보를 제공한다. ConcreteVisitor 클래스가 저장하고 있는 내부 상태는 구조의 순회 과정에서 도출되기도 한다.

- Element: 아규먼트로 Visitor 클래스를 받아들이는 Accept() 오퍼레이션을 정의한다.

- ConcreteElement: 아규먼트로 Visitor 객체를 받아들이는 Accept() 오퍼레이션을 구현한다.

- ObjectStructure: 요소들을 나열하고 방문자로 하여금 이들 요소에 접근하게 하는 인터페이스를 제공한다. ObjectStructure 는 Composite 패턴의 복합 객체일 수도 있고, 리스트나 집합과 같은 컬렉션일 수도 있다.

 

아. 사례 소스코드

- 일반화 된 Visitor 패턴의 활용구조

class Visitor {

        void visit(File file_) {
                System.out.println(file_.getName());
        }

        void visit(Directory dir_) {

                System.out.println(dir_.getName() + "/");
                for(int i=0 ; i < dir_.getSize(); i++)
                        System.out.println(dir_.getChild(i).getName());
 
        }
}

 

댓글