Visitor Pattern은 알고리즘이 처리하는 객체 집합에서 알고리즘은 분리한 Pattern이다. 알고리즘을 분리한 결과 새로운 Operation을 추가하기 위해서 객체 집합을 수정할 필요가 없어졌다.
즉, Open-Closed Principle을 만족할 수 있습니다. Open-Closed Principle은 처리 연산에 대해서는 확장할 수 있지만, 기존 클래스를 수정하지 않아도 된다.
장점이 있으면 단점이 있듯이 Visitor Pattern을 보면 처리의 흐름을 이해하기가 힘들다. 그리고 Visitor Pattern에서 Visitor 역활의 클래스와 Element 역활의 클래스를 살펴보자.
Element 클래스는 Accept 함수를 가지고 Client에게서 작업 객체(Visitor)를 전달받는다.
여기에서 Accept 함수는 전달받은 객체를 다시 작업 수행을 요청한다.
여기에서 Visitor 객체와 Element 객체의 자료형에 따라서 수행되는 작업이 결정이 된다.
이것을 Double-Dispatch라 한다. 일반적인 구조
예제 소스(출처 : Java 언어로 배우는 디자인 패턴 입문. 영진닷컴)
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
abstract class Visitor {
public abstract void visit(File file);
public abstract void visit(Directory directory);
}
interface Element {
public abstract void accept(Visitor v);
}
abstract class Entry implements Element {
public abstract String getName();
public abstract int getSize();
public Entry add(Entry entry) throws FileTreatmentException {
throw new FileTreatmentException();
}
public String toString() {
return getName() + " (" + getSize() + ")";
}
public Iterator<Entry> iterator() throws FileTreatmentException {
throw new FileTreatmentException();
}
}
class File extends Entry {
private String name;
private int size;
public File(String name, int size) {
this.name = name;
this.size = size;
}
public String getName() {
return name;
}
public int getSize() {
return size;
}
public void accept(Visitor v) {
v.visit(this);
}
}
class Directory extends Entry {
private String name;
private ArrayList<Entry> directory = new ArrayList<Entry>();
public Directory(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getSize() {
int size = 0;
Iterator<Entry> it = directory.iterator();
while (it.hasNext()) {
Entry entry = it.next();
size += entry.getSize();
}
return size;
}
public Entry add(Entry entry) {
directory.add(entry);
return this;
}
public Iterator<Entry> iterator() {
return directory.iterator();
}
public void accept(Visitor v) {
v.visit(this);
}
}
class ListVisitor extends Visitor {
private String currentdir = "";
public void visit(File file) {
System.out.println(currentdir + "/" + file);
}
public void visit(Directory directory) {
System.out.println(currentdir + "/" + directory);
String savedir = currentdir;
currentdir = currentdir + "/" + directory.getName();
Iterator<Entry> it = directory.iterator();
while (it.hasNext()) {
Entry entry = it.next();
entry.accept(this);
}
currentdir = savedir;
}
}
class FileTreatmentException extends RuntimeException {
public FileTreatmentException() {
}
public FileTreatmentException(String msg) {
super(msg);
}
}