출처 : 책 - java 언어로 배우는 디자인 패턴 입문
13. Visitor - 데이터 구조를 돌아다니면서 처리하기
1. 목적
- 말 그대로 데이터 구조를 방문(visit)하기 위한 패턴이다.
- 재귀가 활용된다.
Ex) List = { L1, L2 } 라고하면
List가 visitor를 받아들이면 visitor는 List 내부를 돌며 L1, L2도 자신을 받아들이게 한다.
List(visitor) -> L1(visitor), L2(visitor)
2. 예제 - 이전 Composite 패턴 예제가 사용된다.
(1) Visitor - 구현을 위한 부모 추상클래스. visit 메소드를 가지고 있다.
public abstract class Visitor {
public abstract void visit(File file);
public abstract void visit(Directory directory);
}
(2) ListVisitor - Visitor 구현, visit 메소드가 오버로딩 되어있다.
visit(Directory directory) 메소드를 보면 내부를 돌며 accept함수를 실행해 자기를 받아 들이게 한다.
import java.util.Iterator;
public 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 it = directory.iterator();
while (it.hasNext()) { // 내부를 돌며 accept 하게 만드는것이 핵심
Entry entry = (Entry)it.next();
entry.accept(this);
}
currentdir = savedir;
}
}
(3) Element - 방문자를 받아 들이는 부모 인터페이스. accept 메소드를 가지고 있다.
public interface Element {
public abstract void accept(Visitor v);
}
(4) Entry - Element를 상속받는 부모 추상클래스. 즉, visitor를 받아들이는 역할이다.
import java.util.Iterator;
public abstract class Entry implements Element {
public abstract String getName();
public abstract int getSize();
public Entry add(Entry entry) throws FileTreatmentException {
throw new FileTreatmentException();
}
public Iterator iterator() throws FileTreatmentException {
throw new FileTreatmentException();
}
public String toString() {
return getName() + " (" + getSize() + ")";
}
}
(5) File - Entry 자식 클래스. accept함수가 Visitor의 visit을 실행시킨다.
public 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);
}
}
(6) Directory - Entry 자식 클래스. accept 함수가 Visitor의 visit을 실행시키고, visit이 다시 accept를 실행시킨다.
import java.util.Iterator;
import java.util.ArrayList;
public class Directory extends Entry {
private String name;
private ArrayList dir = new ArrayList();
public Directory(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getSize() {
int size = 0;
Iterator it = dir.iterator();
while (it.hasNext()) {
Entry entry = (Entry)it.next();
size += entry.getSize();
}
return size;
}
public Entry add(Entry entry) {
dir.add(entry);
return this;
}
public Iterator iterator() {
return dir.iterator();
}
public void accept(Visitor v) { // 방문자 승낙
v.visit(this);
}
}
(7) Main
public class Main {
public static void main(String[] args) {
try {
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 Kim = new Directory("Kim");
Directory Lee = new Directory("Lee");
Directory Park = new Directory("Park");
usrdir.add(Kim);
usrdir.add(Lee);
usrdir.add(Park);
Kim.add(new File("diary.html", 100));
Kim.add(new File("Composite.java", 200));
Lee.add(new File("memo.tex", 300));
Park.add(new File("game.doc", 400));
Park.add(new File("junk.mail", 500));
rootdir.accept(new ListVisitor());
} catch (FileTreatmentException e) {
e.printStackTrace();
}
}
}
3. 참고사항
cf) The Open-Closed Principle(OCP) : 확장에는 열려있고 수정에 대해서는 닫혀있다.
1. visit의 알고리즘을 바꾸고 싶으면 ListVisitor 외에 다른 visit 구현클래스를 만들어 Element에 넘겨주면 된다.
- OCP 만족
2. Driectory, file 클래스 외에 Device라는 Element 상속 클래스가 늘어나면, 기존 Visit 클래스에
visitor(Device device) 메소드를 추가 해줘야한다. 기존 클래스의 수정이 발생하므로
- OCP를 만족하지 못한다.
'개발 > 디자인 패턴' 카테고리의 다른 글
[Java 언어로 배우는 디자인 패턴 입문] 단순화하기 15. Facade (0) | 2021.01.12 |
---|---|
[Java 언어로 배우는 디자인 패턴 입문] 구조를 돌아다니기 14. Chain of Responsibility (0) | 2021.01.12 |
[Java 언어로 배우는 디자인 패턴 입문] 동일시하기 12. Decorator (0) | 2021.01.11 |
[Java 언어로 배우는 디자인 패턴 입문] 동일시하기 11. Composite (0) | 2021.01.10 |
[Java 언어로 배우는 디자인 패턴 입문] 분리해서 생각하기 10. Strategy (0) | 2021.01.10 |
댓글