일반적 상속구조의 클래스에서

 

각 노드별 하는 overriding 된 함수들이 각각 의 일로 정의되어서 돌아가고 있는데

 

새로운 함수 mm() 을 이 상속 구조에 추가 하고 싶은 경우 ( 또한 노드는 추가 될 수 있다 )

 

 

이런 경우 굉장히 많으 클래스를 추가 시켜야 한다

 

고정된 부분을 기준으로 클래스를 만들다 보니 이런 결과가 나타난다


 

 

how?

 

동적으로 변동 되는 부분을 분리 시킨다!

 

작업의 대상이 되는 것과 작성이 분리 시킨다

 

 

각각 클래스를 따로 만든다

 

visitor class, Make class( 작업 대상이 되는 클래스)

 

 

작업종류 클래스를 visitor class

 


 

만약 트리구조가 있고 그 트리의 노드에는 각각 어떤 타입이 있는지 모를때 이 타입이 무엇인지 체크 하고 싶을때

 

각 노드를 방문하면서 체크해야 한다, ( 각각을 방문한다고해서 visotor 패턴이라 함, 자세한 내용은 계속.. )

 

 

how 방문?

 

 

========================================================

 

visitor* vpCk = new TypeCheckingVisitor ;

 

ConcreteNode->Accept(vpCk);

 

========================================================

 

 

class Node{

   virtual void Accept( visitor* vp )=0;


};

 

로 정의 해놓고

 

서브 노드(Node class 의 서브클래스 )  에 대한 Aceept 가 불릴때 visitor 의 서브 클래스를 넘겨줘

 

class ConcreteNode : public Node {

    void Accept( visitor* vp ){ 

         vp->whatisType(this);

    }

}

 

이렇게 해당 알고리즘을 돌린다

 

이때 알고리즘을 돌리는 클래스(visitor) 쪽에서는 어떤 알고리즘을 돌리는 지를 알고  node 타입(업케스팅된) 의 this  포인터로

 

node 정보를 받기 때문에 이 정보로 알고리즘을 돌리면 된다

 

========================================================

 

class visitor

{

 virtual int whatisType( Node* np )=0;

};

 

class TypeCheckingVisitor : public visitor

{

  virtual int whatisType( Node* np ){

    //타입 체크 정의 부분

  }

};

 

 

 

 

 


 

 

 

근대 위 구조 또한 동일하게 반복될 수 있다 각 노드마다 동일하게 돌아 가는 것이니

동일한 수행 구조라면

 

visitor* vpCk = new TypeCheckingVisitor ;

ConcreteNode->Accept(vpCk);

 

에서 만약 노드마다 어떤 변수에 값을 더해주는 연산을 해야 한다라고 하면 값을 연산해야 하는 visitor 서브 클래스를 만들고

visitor* vpCk = new AddVisitor;

ConcreteNode->Accept(vpCk);

 

이렇게 동일한 구조로 호출해주면 된다

 


 

즉 만들어진 내부구조를 건드리지 않아도 된다는 것이 visitor 패턴의 장점

 

그래서 작업대상은 별로 변경이 이루어지지 않는다

 

그에반해 하고 싶은 작업은 계속 추가 될 수 있다, (추가도 용이하니...)

 

 

- 또한 작업이 한쪽으로 모아진다

 


 

 

일반적인 부모에 추가 하는 상태는 고정되는 상태일때 유용하다

 

 

 


 

 

단점 : 작업 대상이 변경되면  visitor 쪽에서는 거의다 수정해야 됨 !!!!!

대상의 변경이 많을 경우 일반적인 상속구조로 가야 한다

 


 

 

 

STL 컨테이너와 알고리즘을 돌릴 클래스를 따로 작성해 둘을 조합하면서 컨테이너를 순회 하면

이것 또한 visitor 패턴의 응용이 된다

이때 Shared_ptr 사용이 유용할 수 있다 , slice 방지

 

 


 

-interpreter 패턴( 간략한 문법체크 등등의.. )에도 visitor 패턴을 적용 시킬 수 있다

 

-visitor 클래스에서 불리는 알고리즘을 부모에서 정의 할때 인자로 받는 클래스 노드명을

서브노드명으로 고정시켜 다른 것은 받지 않고 해당 노드에 대해 고정된 알고리즘만 돌아가도록

할 수도 있다

 


 

composite 패턴과도 쓰일 수 있다

 

 

class CompositeNode : public Node{

  public :

  virtual void Accept(Visitor& );

  private :

   List<Node*> m_chidren;

}

void CompositeNode::Accept(Visitor& v){

   list<Node*> node(m_children);

 

  for( node.begin(),node.isDone();node.Next(){

    node.CurrentItem()->Accept(v);

  }

  v.VisiteCompositeNode(this);

 

}

 

이때 composite 패턴이 트리와 같은 구조를 갖을 수 있는데 이때 이 노드들을 순회 하는 방법은

 

1. 객체 구조에서 세부 객체들을 찾아 다니면서 Accept() 를 부르는 방법

 

2. visitor 클래스의 연산(함수에) 순회 알고리즘을 적용 할 수 있다

    이때는 순회 하기 위한 알고리즘 중복이 있을 수 있는데, 피할 수 있으면 좋지만 대채로

    노드를 순회방식을 변경할 경우이런 방식을 적용한다

 

3. 별도의 iterator 객체를 생성하여 순회 하도록 하는 경우

    internal iterator  or external iterator 중 효율이 좋은 것으로 돌린다

 

 


 

 

 double dispatch : A 에서 B 를 불렀는데 B 에서 A 를 다시 불러 실행 하는 것

 

Point : 작업종류가 늘어나도 상관없게 하고 싶다

노드는 고정

 

IRC (internet Relay chatting ):

   게임을 하려면 동일한 서버에 붙어야 게임을 할 수 있다

   그런데 이것을 하나의 서버에 있는 것처럼 게임을 할 수 있게 해주는 것

   서버구조 간에 스페닝 트리 구조를 만들고 각 서버 간의 정보를

   서버에서 서버로 옮겨줘 해당 유저 정보를 복사 받는다(실제로는 엄청 느림)

 

  이때 visitor 를 따로 정의 하면

 

RoomListVisitor, ParthnerListVisitor

 

등을 만들어 해당 서버(노드) 에 관한 정보를 받아 리턴해주는 구조를 만들 수 있다

결과는 각 서버(노드)에서 Accept() 에서 수행된 결과를 Accept 안에서  return 해주는 형태로 줄 수도 있다

 

반응형

'디자인패턴과방법론 > 디자인패턴' 카테고리의 다른 글

Bridge 패턴  (0) 2012.11.02
adapter 패턴  (0) 2012.11.02
Template Method 패턴  (0) 2012.11.02
strategy 패턴  (0) 2012.11.02
state 패턴  (0) 2012.11.02

+ Recent posts