CastleJo의 개발일지

Move Accumulation to Visitor (423)

|

개요

어떤 메서드가 이질적인 여러 클래스들로부터 정보를 축적하고 있다면,
각 클래스를 방문해 정보를 축적하는 방문자 객체로 축적 기능을 옮긴다.


동기

Visitor 패턴이 필요한 경우는 거의 없지만, 일단 필요하다면 대체가 불가능하다. 그렇다면 어떤 경우 Visitor 패턴이 필요할까? 방문자 클래스는 주어진 객체 구조에 대해 어떠한 연산을 수행하는데, 이질적인 클래스들을 대상으로 한다. 즉, 방문을 받는 클래스들이 서로 다른 종류의 정보를 담고 그에 대한 인터페이스 또한 서로 다른 경우에 사용한다. 방문자 객체는 이질적인 대상 클래스들로부터 정보를 얻기 위해 이중디스패치를 이요한다. 즉, 대상 클래스가 제공하는 accept(Visitor visitor)와 같은 수납(accept) 메서드의 파라미터를 통해 방문자 객체 자신을 넘기고, 콜백 메서드를 호출하여 정보를 제공하는 것이다.
방문자 클래스가 제공하는 visit...(...) 메서드는 특정 타입의 객체를 파라미터로 받기 때문에, 넘겨받은 객체를 타입 변환할 필요 없이 사용할 수 있다. 따라서 방문자 클래스는 하나의 상속 구조 또는 여러 다른 상속 구조 내의 클래스를 방문할 수 있다.
현업에서는 보통 정보를 축적하기 위해 사용한다. 그런 목적을 위해서라면 Collecting Parameter패턴도 유용하다. 다만 둘의 핵심적인 차이점은 이질적인 클래스로부터 정보를 얼마나 쉽게 축적할 수 있느냐에 있다. 방문자 객체는 이중 디스패치를 사용하기 때문에 전혀 어려움이 없지만, 수집 파라미터 객체는 그렇지 않다.
Visitor를 언제 사용해야 하면, **이질적인 클래스들로 이루어진 어떤 객체 구조를 여러 알고리즘을 통해 처리하고 싶지만 Visitor만큼 단순하고 간결한 해결책이 없을 때 필요하다고 할 수 있다. Visitor 패턴으로 리팩터링 하는 것은 절대 간단하지 않기 때문에 많이 연구하고 확신을 가진 뒤 시작하는 것이 좋다. 또한 방문 대상이 되는 클래스들이 점점 늘어간다면, 해당 패턴을 피하는 것이 좋다. 대상 클래스가 늘어날 때 마다 새 클래스에 대응하는 visit...(...) 메서드를 각각의 Visitor 클래스에 구현해야 되기 때문이다.

장점
  • 이질적인 클래스들로 이루어진 객체 구조를 처리하는 여러 알고리즘들을 수용한다.
  • 하나의 상속 구조 또는 여러 다른 상속 구조 내의 클래스들을 처리할 수 있다.
  • 이질적인 클래스들이 제공하는 메서드들을 타입 변환 없이 호출할 수 있다.
단점
  • 공통 인터페이스를 도입하여 이질적인 클래스들을 동질적으로 만들 수 있다면 괜히 설계만 복잡하게 만드는 것이다.
  • 방문 대상 클래스가 새로 추가되면 ‘수납’메서드도 함께 구현해야 하고 새 클래스에 대응하는 메서드를 각 방문자 클래스에 추가해야 한다.
  • 대상 클래스의 캡슐화 특성을 깨트릴 수 있다.


절차


구현