Visitor pattern : 동일한 타입으로부터 파생된 타입의 행동은 파생된 클래스로부터 재정의하여 원하는 만큼 변경할 수 있다. 하지만 동일한 집합에 속하는 서로다른 타입의 데이터들에 대해서 동일한 인터페이스로 처리할 필요가 있을 때에는 문제가 달라진다. 생각하기 쉬운 한가지 방법은 각 타입마다 처리 알고리즘을 정의하도록 할 수 있다. 하지만, 알고리즘이 변하게되면 관련된 모든 타입들에 대해서 수정해줘야 하며, 비슷한 처리에 대하여 각기 다른 클래스에서 중복되는 처리코드를 가지게되고 행동과 데이터의 분리가 제대로 이루어지지 않게된다. 이러한 문제를 해결하기 위해 알고리즘을 그 구조로부터 분리하여 관리하도록 하며 이를 Visitor pattern 이라 한다.
이 패턴의 구조는 어느날 찾아온 잡상인을 생각하면 이해하기 쉽다. 잡상인은 온갖 물건들을 가지고 돌아다니며 나에게 맞는 물건또한 가지고 있다. 나는 그 많은 물건중 나에게 맞는것만 사면 되는것이다. 잡상인의 입장에서는 수많은 취향의 고객이 있는데, 다양한 취향을 만족시킬 수 있는 물건들을 미리 준비하여 고객들을 찾아다닐 수 있다. 이러한 형태를 클래스 구조로서 표현하게되면 Visitor pattern이 된다.
이러한 구조는 Element의 입장에서 정적인 자신의 타입에 대해 동적인 알고리즘을 선택하게 되며, Visitor의 입장에서 정적으로 정의된 자신의 알고리즘들에 대해서 동적으로 입력된 타입에 대해 처리하기 때문에 double dispatch 구조를 이룬다고 말할 수 있다.
알고리즘과 데이터가 분리되어 관리되기 때문에 방문하는 알고리즘의 변경이 생긴다고 해도 ConcreteVisitor의 클래스 구현부만 바뀔뿐이다. 만약 Element로부터의 추상클래스 구조를 가지며 데이터의 계층화가 잘 되어있다면 -primitiveVisit(element: Element): void 와 같은 형태의 공통인터페이스로부터 더욱 간결한 구조를 형성할 수 있다.
하지만 visit 대상의 추가에 대해서는 인터페이스 구조상의 문제가 발생한다. Visitor 인터페이스는 존재하는 타입들에 대해서 이미 정적으로 visit인터페이스를 정의하였기 때문에 새로운 타입에 대한 visit인터페이스를 추가하는 작업은 소스를 가지고있지 않은 사람이라면 불가능한 일이다. 또한 accept에서 visit으로 넘겨준 레퍼런스는 캡슐화된 엘리먼트 자신이기 때문에 visit 메소드의 입장에서는 알고리즘 처리를 위한 데이터의 접근에 제약을 갖게된다. 미리 데이터 처리를 위해 사용가능한 인터페이스를 제공해 주어야 하며 ConcreteElement 안에서 직접적으로 처리할때보다 연산에 오버헤드가 뒤따르게된다. 또한 Element가 데이터접근에 충분한 인터페이스를 제공하지 않는다면 강점중 하나인 알고리즘의 수정에도 제약이되버린다. 즉, 집합안에 포함되는 클래스 타입이 모호하고 데이터 구조 또한 명확하지 않다면 Visitor pattern이 줄 수 있는 장점은 그리 크지않다는 의미이다. 이러한 단점들은 Element와 그 하위클래스, Visitor와 그 하위클래스간의 결합도에 대한 이슈로 초기 설계와 이후의 확장성에 대한 문제를 가져오는 부분이다.
단점이 조금 크다고 느껴지지만 Visitor pattern이 가지는 처리 알고리즘과 대상의 구분은 클래스 구조를 명확하게 표현한다는 점에서 의미있다고 본다.
한줄요약 : 잘 짜여진 구조에 안정감있게 행동하지만, 예상못한 난입에는 흔들리는 유연성이 부족한 패턴이다.
'Coding Note' 카테고리의 다른 글
[C++] virtual inheritance (0) | 2013.06.29 |
---|---|
[Design pattern] 디자인 패턴이란 (6) | 2013.03.28 |
[Design pattern] Template method (0) | 2013.03.27 |
[Design pattern] Memento (0) | 2013.03.26 |
[Design pattern] Mediator (0) | 2013.03.25 |