Visitor 클래스
package kch;
public abstract class Visitor {
public abstract void visit(File file);
public abstract void visit(Directory directory);
}
Element 인터페이스
package kch;
public interface Element {//방문자를 받아들임.
public abstract void accept(Visitor v);
}
Entry 클래스
package kch;
import java.util.Iterator;
public abstract class Entry implementsElement{
public abstract String getName();
public abstract int getSize();
publicEntry add(Entry entry) throws FileTreatmentException{
//Entry를 추가하는 것 Directory클래스는 add를 재정의 할 것이고
// File클래스는 add를 그대로 받을 것이다.
//이유는 Directory안에는 더 추가 할 수 있지만
//File은 더 추가 할 수 없기 때문이다.
throw new FileTreatmentException();
}
public Iteratoriterator() throws FileTreatmentException{
throw new FileTreatmentException();
}
publicString toString(){
returngetName() +" (" + getSize() + ")";//문자열 표현
}
}
FileTratmentException : 단순히 예외 처리를 위한클래스.
package kch;
public class FileTreatmentException extends RuntimeException{
publicFileTreatmentException(){
}
publicFileTreatmentException(String msg){
super(msg);
}
}
File 클래스
package kch;
public class File extendsEntry{
privateString name;
private int size;
publicFile(String name, int size){
this.name = name;
this.size = size;
}
publicString getName(){
return name;
}
public int getSize(){
return size;
}
public void accept(Visitor v){//방문자 승낙을 함.
v.visit(this);
}
}
Directory 클래스
여기서 파일의 추가 관리와 Visitor패턴을 이용하기 위한 accept 메소드의 출발점이 됩니다.
package kch;
import java.util.ArrayList;
import java.util.Iterator;
public class Directory extendsEntry{
privateString name;
private ArrayListdir = new ArrayList();
publicDirectory(String name){
this.name = name;
}
publicString 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;
}
//Directory클래스는 하위에 Directory나 File을 추가 할 수 있으므로 add를 오버라이드한다.
publicEntry add(Entry entry){
dir.add(entry);//arrayList에 추가.
return this;
}
//dir의 iterator를 가져온다.
public Iteratoriterator(){
return dir.iterator();
}
//방문자 승낙
//이부분이 파일의 모든 내용을보여줄때 출발점이 됩니다.
//바로 ListVistior함수의 vist함수를 호출하게된다.
@Override
public void accept(Visitor v) {
// TODO Auto-generated method stub
v.visit(this);
}
}
ListVisitor 클래스
package kch;
import java.util.Iterator;
public class ListVisitor extendsVisitor{
privateString currentdir = "";//현재 주목하는 디렉터리 이름을 저장함.
//File클래스 인스턴스가 들어오면 더이상 재귀적인 호출을 하지 않는다.
//왜냐하면 accept를 호출하지 않기 때문에.
@Override
public void visit(File file) {
// TODO Auto-generated method stub
System.out.println(currentdir +"/" + file);
}
//Directory클래스 인스턴스가 들어오면 재귀적인 호출이 이루어진다.
//이유는 다시 entry.accept(this); 때문에 다시 Directory클래스의accept메소드를 호출하게되는데
//다시 accept메소드는 ListVisitor클래스의 visit 메소드를 호출하게되므로
//이때는 인스턴스에 따라서 틀리겠지만Directroy클래스면
//public void visit(Directory directory) {가 호출되고
//아니면 public void visit(File file) {가 호출된다.
@Override
public void visit(Directory directory) {
// TODO Auto-generated method stub
//System.out.println(currentdir + "/" +directory);//이부분을 주석 풀면 File이나올때까지만 출력함.
String savedir = currentdir;
currentdir = currentdir + "/" + directory.getName();
Iterator it =directory.iterator();//ArrayList를 가져온다.
while(it.hasNext()){//다음 항목이있으면
Entry entry =(Entry)it.next();//다음의 것을 entry에 넣음
entry.accept(this);
}
currentdir =savedir;
}
}
Main 클래스
package kch;
public class Main {
public static void main(String[] args){
try{
System.out.println("Makingroot 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));
//accept가 핵심.
//맨처음에 /root (30000)가 출력될때 Entry 클래스의 toString 때문에 root가 출력됨.
//이제부터가 중요함
///root/bin (30000) 출력은
//ListVisitor클래스에서 entry.accept(this); 이라인이 실행되면
//Directory클래스의 accept에 가보면 Visitor함수의 visit을 호출한다.
//즉 ListVisitor의 visit메소드가 호출이 된다.
//만약에 이때 인스턴스가 File이냐와 Directory냐에 따라서 호출되는메소드가 틀린데
//File이면 출력이 마무리된것이고
//Directory면 재귀적으로 계속 파일이 나올때까지 안으로 파고들 것이다.
rootdir.accept(new ListVisitor());
System.out.println("");
System.out.println("Makinguser 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("Compositie.java", 200));
Lee.add(new File("memo.txt", 300));
Park.add(new File("game.doc", 400));
Park.add(new File("junk.mail", 500));
rootdir.accept(new ListVisitor());
}catch(FileTreatmentExceptione){
e.printStackTrace();
}
}
}
Visitor 패턴의 목적은 처리를 데이터 구조에서 분리하는 일입니다.
여기서 처리하는 부분은 ListVisitor입니다. 디렉토리냐 파일이냐에 대해서 표시하는 것을 처
리하는 부분이었습니다. 데이터 구조는 Directory클래스와 File 클래스가 담당하고 있었구
요.
결과적으로 Visitor패턴은File클래스나 Directory클래스의 부품으로서의 독립성을 높여주었습니다.
만약에 HardDisk라는 클래스를 File과 Directory의 형제클래스로 추가한다면
HardDisk클래스는 독립적으로 클래스 확장이 되고 이에 대해서표시 처리는 ListVisitor에서
만 추가적으로 처리하면 됩니다.
'프로그래밍 > 자바 디자인패턴' 카테고리의 다른 글
디자인 패턴 Template Method 패턴 (0) | 2012.08.03 |
---|---|
디자인 패턴 위임에 의한 Adapter 패턴(인스턴스를 이용한) (0) | 2012.08.03 |
디자인 패턴 Adapter패턴 상속을 사용한 Adapter패턴 (0) | 2012.08.03 |
디자인패턴 Chain of Responsibility 패턴 (0) | 2012.08.02 |
디자인 패턴 Decorator 패턴 (0) | 2012.08.01 |
디자인 패턴 Composite 패턴 (0) | 2012.08.01 |
디자인 패턴 Strategy 패턴 (0) | 2012.08.01 |
디자인 패턴 Bridge 패턴 (0) | 2012.08.01 |