비지터(Visitor) 패턴
다양한 객체에 새로운 기능을 추가해야 하는데 캡슐화가 별로 중요하지 않다면 비지터 패턴을 쓴다.
비지터 패턴은 객체 구조를 정의하고, 이 구조를 기반으로 알고리즘을 캡슐화하여 새로운 알고리즘을 추가할 때 기존 코드를 수정하지 않고 확장하는 디자인 패턴 중 하나이다.
주로 데이터 구조와 처리를 분리하여 새로운 처리를 쉽게 추가하고 확장할 수 있도록 한다.
특징
- 알고리즘 분리
- 알고리즘을 객체 구조에서 분리하여 캡슐화하고, 각 알고리즘을 방문자(Visitor)로 정의한다.
- 확장성 향상
- 새로운 알고리즘을 추가할 때 기존 코드를 수정하지 않고 확장할 수 있다.
구조

- Visitor(방문자)
- 객체 구조를 방문하여 각 구조에 대한 알고리즘을 수행하는 인터페이스를 정의한다.
- ConcreteVisitor
Visitor
인터페이스를 구현하고, 실제 알고리즘을 구현한다.
- Element(요소)
- 방문자가 방문하는 객체의 언터페이스를 정의한다.
- ConcreteElement
Element
인터페이스를 구현하고, 방문자의 방문을 받아들이는 메서드를 구현한다.
- ObjectStructure(객체 구조)
- 여러 요소를 포함하는 객체 구조를 정의하고, 방문자를 받아들이는 메서드를 제공한다.
예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
| // Visitor
public interface Visitor {
void visit(ConcreteElementA element);
void visit(ConcreteElementB element);
}
// ConcreteVisitor
public class ConcreteVisitor implements Visitor {
@Override
public void visit(ConcreteElementA element) {
System.out.println("Visit ConcreteElementA");
}
@Override
public void visit(ConcreteElementB element) {
System.out.println("Visit ConcreteElementB");
}
}
// Element
public interface Element {
void accept(Visitor visitor);
}
// ConcreteElement
public class ConcreteElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// ConcreteElement
public class ConcreteElementB implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// ObjectStructure
public class ObjectStructure {
private List<Element> elements = new ArrayList<>();
public void addElement(Element element) {
elements.add(element);
}
public void accept(Visitor visitor) {
for (Element element : elements) {
element.accept(visitor);
}
}
}
// Client
public class Client {
public static void main(String[] args) {
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.addElement(new ConcreteElementA());
objectStructure.addElement(new ConcreteElementB());
Visitor visitor = new ConcreteVisitor();
objectStructure.accept(visitor);
}
}
|
장단점
장점
- 알고리즘 추가의 용이성
- 새로운 알고리즘을 추가하거나 기존 알고리즘을 수정할 때, 기존 코드를 건드리지 않고 확장할 수 있다.
- 비교적 손쉽게 새로운 기능을 추가할 수 있다.
- 구조와 알고리즘의 분리
- 비지터가 수행하는 기능과 관련된 코드를 한곳에 모아 둘 수 있다.
- 객체 구조와 알고리즘을 분리하여 코드를 보다 모듈화하고 유지보수성을 높일 수 있다.
단점
- 캡슐화 불가능
- 비지터를 사용하면 복합 클래스의 캡슐화가 깨진다.
- 구조 변경 어려움
- 컬렉션 내의 모든 항목에 접근하는 트래버서(클라이언트)가 있으므로 복합 구조를 변경하기가 더 어려워진다.
- 클래스 증가
- 새로운 요소나 알고리즘을 추가할 때마다 클래스의 수가 늘어난다.
- 이로 인해 클래스의 수가 많아지면 유지보수가 어려워질 수 있다.