โ๏ธ Java Design-Pattern XIV - Visitor
โ๏ธ Java Design-Pattern XIV - 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.