โ๏ธ Java Design-Pattern 14 - Visitor
โ๏ธ Java Design-Pattern 14 - Visitor
๐
ใJAVA ์ธ์ด๋ก ๋ฐฐ์ฐ๋ ๋์์ธ ํจํด : ์ฝ๊ฒ ๋ฐฐ์ฐ๋ GoF์ 23๊ฐ์ง ๋์์ธ ํจํดใ๋ฅผ ์ฝ๊ณ ์ ๋ฆฌํ ๊ธ์ ๋๋ค.
Visitor ํจํด์ด๋?
- ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ์ฒ๋ฆฌ๋ฅผ ๋ถ๋ฆฌํ๋ค.
- ์ฆ ๋ฐ์ดํฐ ๊ตฌ์กฐ ์์ ๋์๋ค๋๋ย ๋ฐฉ๋ฌธ์๋ฅผ ์ค๋นํ์ฌ ์ฒ๋ฆฌ๋ฅผ ๋งก๊ธด๋ค.
- ์๋ก์ด ์ฒ๋ฆฌ๋ฅผ ์ถ๊ฐํ๊ณ ์ถ์ ๋๋ ์๋ก์ด ๋ฐฉ๋ฌธ์๋ฅผ ๋ง๋ ๋ค.
- ๋ฐ์ดํฐ ๊ตฌ์กฐ์์๋ ๋ฌธ์ ๋๋๋ฆฌ๋ ๋ฐฉ๋ฌธ์๋ฅผ ๋ฐ๋๋ค.
์์ ํ๋ก๊ทธ๋จ
- ๋ค์์ ํ์ผ๊ณผ ๋๋ ํฐ๋ฆฌ๋ก ๊ตฌ์ฑ๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ ์์ ๋ฐฉ๋ฌธ์๊ฐ ๋์๋ค๋๋ฉฐ ํ์ผ ๋ชฉ๋ก์ ํ์ํ๋ ํ๋ก๊ทธ๋จ์ด๋ค.
Visitorย ํด๋์ค
1
2
3
4
public abstract class Visitor {
public abstract void visit(File file);
public abstract void visit(Directory directory);
}
- ๋ฐฉ๋ฌธ์๋ฅผ ๋ํ๋ด๋ ์ถ์ ํด๋์ค์ด๋ค.
- ์ด ๋ฐฉ๋ฌธ์๋ ๋ฐฉ๋ฌธํ๋ ๊ณณ์ ๋ฐ์ดํฐ๊ตฌ์กฐ์ ์์กดํ๋ค. ์ฌ๊ธฐ์๋ย
File๊ณผยDirectory์ ํด๋นํ๋ค. visitย ๋ฉ์๋๊ฐ ์ค๋ฒ๋ก๋ ๋์ด ์๋ค.
Elementย ์ธํฐํ์ด์ค
1
2
3
public interface Element {
public abstract void accept(Visitor v);
}
- ๋ฐฉ๋ฌธ์๋ฅผ ๋ฐ์๋ค์ด๋ ์ธํฐํ์ด์ค์ด๋ค.
Entryย ํด๋์ค
1
2
3
4
5
6
7
8
9
public abstract class Entry implements Element {
public abstract String getName();
public abstract int getSize();
@Override
public String toString() {
return getName() + " (" + getSize() + ")";
}
}
Elementย ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ์ถ์ ํด๋์ค์ด๋ค.- ์ค์ ๋ก ์ด ํด๋์ค๋ฅผ ๊ตฌ์ฒดํํ๋ ๊ฒ์ย
Fileย ๋๋ยDirectoryย ํด๋์ค์ด๋ค.
Fileย ํด๋์ค
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class File extends Entry {
private String name;
private int size;
public File(String name, int size) {
this.name = name;
this.size = size;
}
@Override
public String getName() {
return name;
}
@Override
public int getSize() {
return size;
}
@Override
public void accept(Visitor v) {
v.visit(this);
}
}
acceptย ๋ฉ์๋๋ ๋ฐฉ๋ฌธ์์ยvisitย ๋ฉ์๋๋ฅผ ํธ์ถํจ์ผ๋ก์จ ๋ฐฉ๋ฌธํยFileย ์ธ์คํด์ค๋ฅผ ๋ฐฉ๋ฌธ์์๊ฒ ์๋ ค์ค๋ค.
Directoryย ํด๋์ค
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
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Directory extends Entry implements Iterable<Entry> {
private String name;
private List<Entry> directory = new ArrayList<>();
public Directory(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public int getSize() {
int size = 0;
for (Entry entry : directory) {
size += entry.getSize();
}
return size;
}
public Entry add(Entry entry) {
directory.add(entry);
return this;
}
@Override
public Iterator<Entry> iterator() {
return directory.iterator();
}
@Override
public void accept(Visitor v) {
v.visit(this)
}
}
iteratorย ๋ฉ์๋๋ ๋๋ ํฐ๋ฆฌ์ ํฌํจ๋ ๋๋ ํฐ๋ฆฌ ์ํธ๋ฆฌ(ํ์ผ, ๋๋ ํฐ๋ฆฌ) ๋ชฉ๋ก์ ์ป๊ธฐ ์ํยIterator<Entry>๋ฅผ ๋ฐํํ๋ค.acceptย ๋ฉ์๋๋ ๋ฐฉ๋ฌธ์์ยvisitย ๋ฉ์๋๋ฅผ ํธ์ถํจ์ผ๋ก์จ ๋ฐฉ๋ฌธํยDirectoryย ์ธ์คํด์ค๋ฅผ ๋ฐฉ๋ฌธ์์๊ฒ ์๋ ค์ค๋ค.
ListVisitorย ํด๋์ค
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ListVisitor extends Visitor {
private String currentDir = "";
@Override
public void visit(File file) {
System.out.println(currentDir + "/" + file);
}
@Override
public void visit(Directory directory) {
System.out.println(currentDir + "/" + directory);
String saveDir = currentDir;
currentDir = currentDir + "/" + directory.getName();
for (Entry entry : directory) {
entry.accept(this);
}
currentDir = saveDir;
}
}
Visitorย ํด๋์ค๋ฅผ ๊ตฌ์ฒดํํ ํ์ ํด๋์ค์ด๋ค.- ์ฆ ์ค์ ๋ฐฉ๋ฌธ์ ์ญํ ์ ์ํํ๋ค.
currentDirย ํ๋์๋ ํ์ฌ ๋ฐ๋ผ๋ณด๋ ๋๋ ํฐ๋ฆฌ ์ด๋ฆ์ ์ ์ฅํ๋ค.visitย ๋ฉ์๋๋ ๊ฐ ์ธ์คํด์ค์ ํด์ผ ํ ์ฒ๋ฆฌ๋ฅผ ๊ธฐ์ ํ์๋ค.- ๊ฒฐ๊ตญย
acceptย ๋ฉ์๋์ยvisitย ๋ฉ์๋๋ ์๋ก๋ฅผ ํธ์ถํ๊ฒ ๋๋ค. - ๋ณดํต ์ฌ๊ท์ ํธ์ถ์ ์๊ธฐ ์์ ์ ํธ์ถํ๋ ๋ฐ๋ฉด, ์ด๋ ์๋นํ ๋ณต์กํ ์ฌ๊ท์ ๋ฉ์๋ ํธ์ถ์ด๋ค.
Mainย ํด๋์ค
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
public class Main {
public static void main(String[] args) {
System.out.println("Making root entries...");
Directory rootDir = new Directory("root");
Directory binDir = new Directory("bin");
Directory tmpDir = new Directory("tmp");
Directory usrDir = new Directory("usr");
rootDir.add(binDir);
rootDir.add(tmpDir);
rootDir.add(usrDir);
binDir.add(new File("vi", 10000));
binDir.add(new File("latex", 20000));
rootDir.accept(new ListVisitor());
System.out.println();
System.out.println("Making user entries...");
Directory youngjin = new Directory("youngjin");
Directory gildong = new Directory("gildong");
Directory dojun = new Directory("dojun");
usrDir.add(youngjin);
usrDir.add(gildong);
usrDir.add(dojun);
youngjin.add(new File("diary.html", 100));
youngjin.add(new File("Composite.java", 200));
gildong.add(new File("memo.txt", 300));
dojun.add(new File("game.doc", 400));
dojun.add(new File("junk.mail", 500));
rootDir.accept(new ListVisitor());
}
}
Compositeย ํจํด์ยMainย ํด๋์ค์ ๊ฑฐ์ ๋์ผํ๋ค.- ๋จย
Compositeย ํจํด์์๋ยprintList๋ผ๋ ๋ฉ์๋๋ก ๋๋ ํฐ๋ฆฌ๋ฅผ ์ถ๋ ฅํ๋ ๋ฐ๋ฉด, ํด๋น ํจํด์์๋ ๋ฐฉ๋ฌธ์๊ฐ ๋๋ ํฐ๋ฆฌ๋ฅผ ์ถ๋ ฅํ๋ค. - ๋๋ ํฐ๋ฆฌ ์ถ๋ ฅ๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ ๋ด์ ๊ฐ ์์์ ๋ํ ์ฒ๋ฆฌ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
Visitor์ย Element์ ์ํธ ํธํก
File,ยDirectoryย ์ธ์คํด์ค์ ๋ํด์๋ยacceptย ๋ฉ์๋๊ฐ ํธ์ถ๋๋ค.acceptย ๋ฉ์๋๋ ๊ฐ ์ธ์คํด์ค์์ ํ ๋ฒ๋ง ํธ์ถ๋๋ค.ListVisitor์ ์ธ์คํด์ค์ ๋ํด์๋ยvisitย ๋ฉ์๋๊ฐ ํธ์ถ๋๋ค.visitย ๋ฉ์๋๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒ์ ํ๋์ยListVisitorย ํด๋์ค์ ์ธ์คํด์ค์ด๋ค.- ๋ฐฉ๋ฌธ์ย
ListVisitor์๊ฒยvisitย ๋ฉ์๋ ์ฒ๋ฆฌ๊ฐ ์ง์ค๋๋ ๋ชจ์ต์ ์ดํดํด์ผ ํ๋ค.
Visitย ํจํด์ ๋ฑ์ฅ์ธ๋ฌผ
Visitorย ํด๋์ค
- ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ๊ตฌ์ฒด์ ์ธ ํด๋์ค ๋ณ๋กย
visitย ์ถ์ ๋ฉ์๋๋ฅผ ์ ์ธํ๋ ์ถ์ ํด๋์ค์ด๋ค. - ๋ฐฉ๋ฌธ์ย
Visitorย ์ญํ ์ ๋งก๋๋ค.
ListVisitorย ํด๋์ค
- ๊ตฌ์ฒด์ ์ธ ๋ฐฉ๋ฌธ์ย
ConcreteVisitorย ์ญํ ์ ๋งก์ ๋ฐฉ๋ฌธ์์ ์ธํฐํ์ด์คยAPI๋ฅผ ๊ตฌํํ๋ค. ListVisitor์์ยcurrentDirย ํ๋ ๊ฐ์ด ๋ณํํ ๊ฒ์ฒ๋ผยvisitย ๋ฉ์๋๋ฅผ ์ฒ๋ฆฌํ๋ ์ค์ ๊ตฌ์ฒด์ ์ธ ๋ฐฉ๋ฌธ์ ์ญํ ์ ๋ด๋ถ ์ํ๊ฐ ๋ณํํ๊ธฐ๋ ํ๋ค.
Elementย ์ธํฐํ์ด์ค
- ์์ย
Elementย ์ญํ ์ ๋งก์ ๋ฐฉ๋ฌธ์๊ฐ ๋ฐฉ๋ฌธํ ๊ณณ์ ๋ํ๋ด๋ฉฐ, ๋ฐฉ๋ฌธ์๋ฅผ ๋ฐ์๋ค์ด๋ยacceptย ๋ฉ์๋๋ฅผ ์ ์ธํ๋ค.
File,ย Directorย ํด๋์ค
Element์ ์ธํฐํ์ด์คยAPI๋ฅผ ๊ตฌํํ๋ ๊ตฌ์ฒด์ ์ธ ์์ยConcreteElementย ์ญํ ์ ๋งก์๋ค.
Directoryย ํด๋์ค
- ํด๋น ํด๋์ค๋ ๊ตฌ์ฒด์ ์ธ ์์ ์ญํ ๊ณผ ํจ๊ป ์ค๋ธ์ ํธ ๊ตฌ์กฐย
ObjectStructureย ์ญํ ์ ๋งก์๋ค. - ์ฆ 1์ธ 2์ญ์ ๋งก์๋ค.
- ๊ตฌ์ฒด์ ์ธ ๋ฐฉ๋ฌธ์๊ฐ ๊ฐ๊ฐ์ ์์๋ฅผ ์ทจ๊ธํ ์ ์๋ ๋ฉ์๋๋ฅผ ๊ฐ์ถ๊ณ ์๋ค.
- ์์ ํ๋ก๊ทธ๋จ์์๋ย
iteratorย ๋ฉ์๋๋ฅผ ํตํด ์์ ์งํฉ์ ๋ค๋ฃฌ๋ค.
์ฑ ์์ ์ ์ํ๋ ํํธ
์ ์ด๋ ๊ฒ ๋ณต์กํ ์ผ์ ํ๋๊ฐ?
element๋ยvisitor๋ฅผยacceptย ํ๊ณ ,ยvisitor๋ยelement๋ฅผยvisitย ํ๋ค.- ์ด๊ฒ์ ๋๋ธ ๋์คํจ์น๋ผ๊ณ ํ๋ค.
Visitorย ํจํด์ ๋ชฉ์ ์ ์ฒ๋ฆฌ๋ฅผ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ๋ถ๋ฆฌํ๋ ๊ฒ์ด๋ค.ย- ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ์์๋ฅผ ์งํฉ์ผ๋ก ์ ์ํ๊ฑฐ๋ ์์ ์ฌ์ด๋ฅผ ์ฐ๊ฒฐํด์ฃผ๋ ์ญํ ์ ํ๋๋ฐ, ๊ทธ ์ฒ๋ฆฌ๋ ๋ฐฉ๋ฌธ์ย
API์ ๊ตฌ์ฒด์ ์ธ ๋ฐฉ๋ฌธ์๋ฅผ ๋์ดยFile,ยDirectoryย ํด๋์ค์ ๋ถํ์ผ๋ก์์ ๋ ๋ฆฝ์ฑ์ ๋์ผ ์ ์๋ค. - ๊ฐ๋ น ์ฒ๋ฆฌ ๋ด์ฉ์ย
File,ยDirectoryย ํด๋์ค์ ๋ฉ์๋๋ก ํ๋ก๊ทธ๋จ์ ์์ฑํด๋ฒ๋ฆด ๊ฒฝ์ฐ ์๋ก์ด ์ฒ๋ฆฌ๋ฅผ ์ถ๊ฐํ๊ณ ์ถ๋ค๋ฉดยFile,ยDirectoryย ํด๋์ค๋ฅผ ์์ ํด์ผ ํ๋ค.
The Open-Closed Principle : ํ์ฅ์ ๋ํด์๋ ์ด๊ณ , ์์ ์ ๋ํด์๋ ๋ซ๋๋ค.
OCPย ์์น์ ์ํ๋ฉด ํด๋์ค๋ฅผ ์ค๊ณํ ๋๋ ํน๋ณํ ์ด์ ๊ฐ ์๋ ํ ํ์ฅ์ ํ์ฉํด์ผ ํ๋ค.- ๋์์ ํ์ฅํ ๋๋ง๋ค ๊ธฐ์กด ํด๋์ค๋ฅผ ์์ ํ ํ์๊ฐ ์๊ฒ ํด์ผ ํ๋ค.
- ํด๋์ค์ ๋ํ ์๊ตฌ๋ ๊ธฐ๋ฅ์ ํ์ฅํ๋ ์ชฝ์ผ๋ก ๋น๋ฒํ๊ฒ ๋ณํํ๋ค.
- ๊ทธ๋ ๊ธฐ์ ๊ธฐ๋ฅ์ ํ์ฅํ ์ ์์ผ๋ฉด ๊ณค๋ํ๊ณ , ์ด๋ฏธ ๋ง๋ค์ด ํ ์คํธ๊น์ง ๋ง์น ํด๋์ค๋ฅผ ์์ ํ๋ฉด ์ํํธ์จ์ด์ ํ์ง์ ๋จ์ด๋จ๋ฆด ์ํ์ด ์๋ค.
- ๊ถ๊ทน์ ์ผ๋ก๋ย
OCPย ์์น์ด ๋์์ธ ํจํด, ๊ฐ์ฒด ์งํฅ์ ๋ชฉ์ ์ด๋ค.
์ญํ ์ถ๊ฐ
- ๊ตฌ์ฒด์ ์ธ ๋ฐฉ๋ฌธ์ ์ญํ ์ถ๊ฐ๋ ์ฝ๋ค.
- ๊ตฌ์ฒด์ ์ธ ์ฒ๋ฆฌ๋ ๊ตฌ์ฒด์ ์ธ ๋ฐฉ๋ฌธ์ ์ญํ ์ ๋งก๊ธฐ๊ณ , ๊ทธ ์ฒ๋ฆฌ๋ฅผ ์ํด ๊ตฌ์ฒด์ ์ธ ์์ ์ญํ ์ ์์ ํ ํ์๊ฐ ์ ํ ์๊ธฐ ๋๋ฌธ์ด๋ค.
- ๋ฐ๋ฉด ๊ตฌ์ฒด์ ์ธ ์์ ์ญํ ์ถ๊ฐ๋ ์ด๋ ต๋ค.
- ๊ฐ๋ นย
Entryย ํด๋์ค์ ํ์ ํด๋์ค๋กยDeviceย ํด๋์ค๋ฅผ ๋ง๋ ๋ค๊ณ ํ๋ฉดยVisitorย ํด๋์ค์ยvisit(Device device)ย ๋ฉ์๋๋ฅผ ์๋ก ๋ง๋ค์ด์ผ ํ๊ณ ,ยVisitorย ํด๋์ค์ ํ์ ํด๋์ค์ ๋ชจ๋ยvisit(Device device)ย ๋ฉ์๋๋ฅผ ๊ตฌํํด์ผ ํ๋ค.
๋ฐฉ๋ฌธ์๊ฐ ์ฒ๋ฆฌํ๋ ค๋ฉด ๋ฌด์์ด ํ์ํ๊ฐ?
- ๋ฐฉ๋ฌธ์๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ์์ ํ์ํ ์ ๋ณด๋ฅผ ์ทจ๋ํ์ฌ ๋์ํ๋ค.
- ํ์ํ ์ ๋ณด๋ฅผ ์ป์ง ๋ชปํ๋ฉด ๋ฐฉ๋ฌธ์๊ฐ ์ ๋๋ก ์ผ์ ํ ์ ์๋ค.
- ๋ฐ๋ฉด ๊ณต๊ฐํ์ง ๋ง์์ผ ํ ์ ๋ณด๊น์ง ๊ณต๊ฐํด ๋ฒ๋ฆฌ๋ฉด, ๋ฏธ๋์ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๋ณ๊ฒฝํ๊ธฐ๊ฐ ์ด๋ ค์์ง๋ค.
- ๊ฐ๋ น ์์ ํ๋ก๊ทธ๋จ์์๋ย
visit(Directory directory)ย ์์์ ๊ฐ๊ฐ์ ๋๋ ํฐ๋ฆฌ ์ํธ๋ฆฌ์ ๋ํดยacceptย ๋ฉ์๋๋ฅผ ์คํํ๊ธฐ ์ํดยiteratorย ๋ฉ์๋๋ฅผ ์ ๊ณตํด์ผ ํ๋ค.
This post is licensed under CC BY 4.0 by the author.


