프로그래밍/자바 디자인패턴

디자인 패턴 Visitor 패턴

가카리 2012. 8. 1. 22:18
반응형

 

 

 

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 호출한다.

                       // ListVisitorvisit메소드가 호출이 된다.

                       //만약에 이때 인스턴스가 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에서

만 추가적으로 처리하면 됩니다.

 

 

 

반응형