티스토리 뷰

반응형

방문자 패턴 (Visitor Pattern)


데이터 구조와 연산을 분리하여 데이터 구조의 원소들을 변경하지 않고 새로운 연산을 추가 할 수 있습니다. 새로운 연산을 추가하려면 새로운 방문자를 추가하기만 하면 됩니다.

 

 

방문자 패턴 구조 (예제)


 

오른쪽에는 Composite 패턴으로 구현 된 File과 Directory로 이루어진 데이터 구조가 있습니다. 다만, 방문자를 수용하기 위해 Element 인터페이스를 상속받아서 accept() 메서드를 각각 구현하고 있으며 각 element의 경로를 구하는 연산 부분이 방문자에서 이루어집니다. 왼쪽에는 방문자로 데이터 구조를 방문하면서 필요한 연산을 수행합니다. 각 element에 접근하기 위한 visit메서드를 오버라이딩 및 오버로딩을 하고 있습니다.

 

 

소스코드


Element.interface 와 Entry

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface Element {
    public abstract void accept(Visitor v);
}
 
public abstract class Entry implements Element {
    String name;
    public Entry(String name)
    {
        this.name = name;
    }
    public abstract void add(Entry entry);
}
 

방문자를 수용하기 위한 accept() 메서드를 정의하는 인터페이스 Element와 File과 Directory가 공통적으로 구현 해야 할 인터페이스를 정의하는 상위 클래스 Entry를 정의합니다.

 

Direcotry.java 와 File.java 

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
public class File extends Entry {
    public File(String name)
    {
        super(name);
    }
    public void add(Entry entry){}
    public void accept(Visitor v)
    {
        v.visit(this);
    }
}
 
public class Directory extends Entry {
    
    ArrayList<Entry> directory = new ArrayList();    //자식 객체를 담기 위한 ArrayList
    
    public Directory(String name)
    {
        super(name);
    }
    public void add(Entry entry)                    //자식 객체 추가
    {
        directory.add(entry);
    }
    public void accept(Visitor v)
    {
        v.visit(this);            //어느 visit() 메서드를 호출할지 결정납니다.
    }
}

 

데이터 구조에 해당하는 File과 Directory입니다. 앞서 Composite패턴에서는 경로를 구하는 연산을 이곳에서 이루어졌던 반면에 지금은 방문자를 수용하는 accept() 메서드를 구현하고 있습니다. accept() 내용은 매개변수로 받은 Visitor 객체를 통하여 자기 자신을 인자로 하는 visit() 메서드를 호출 하고 있습니다. 살펴 볼 것은 visit() 메서드는 File과 Directory에서 자기 자신을 인자로 해서 호출이 이루어지고 있습니다. 이때 File에 대한 visit() 메서드가 호출이 될지 Directory에 대한 visit()가 호출이 될지 결정이 됩니다.

 

Visitor.java 와 ViewVisitor.java

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 abstract class Visitor {
 
    public abstract void visit(File file);
    public abstract void visit(Directory directory);
}
 
public class ViewVisitor extends Visitor {
    
    private String Path="";
    public void visit(File file)
    {
        System.out.println(Path + "/"+file.name);
    }
    public void visit(Directory dic)
    {
        Path = Path + "/" + dic.name;
        System.out.println(Path);
        for(int i=0; i<dic.directory.size();i++)
        {
            dic.directory.get(i).accept(this);
        }
    }
 
}

Visitor 클래스는 방문자들이 데이터 구조를 방문하기 위한 인터페이스를 정의하고 있습니다. ViewVisitor 클래스는 데이터 구조를 방문하면서 각 Element의 현재 경로를 출력해주는 역할을 합니다. visit() 라는 같은 이름으로 하나는 Directory를 인자로 갖는 다른 하나는 File를 인자로 갖는 메서드를 오버로딩이 되어 있는 상태입니다.

 

Main.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Main {
 
    public static void main(String argsp[])
    {    
        Directory root = new Directory("root");
        Directory bin = new Directory("bin");
        Directory Lkt = new Directory("Lkt");
        File file1 = new File("file1");
        File file2 = new File("file2");
        File file3 = new File("file3");
        File file4 = new File("file4");
        
        root.add(file1);
        bin.add(file2);
        bin.add(file3);
        Lkt.add(file4);
        root.add(Lkt);
        root.add(bin);
        
        root.accept(new ViewVisitor());    //경로 출력
    }
}

 

실제 메인 영역에서 방문자 패턴을 사용하는 모습입니다.

 

 

 

이처럼 Visitor 패턴은 데이터 구조와 연산을 분리함으로써 데이터 구조를 변경하지 않으면서 새로운 연산을 쉽게 할 수 있습니다. 만약 새로운 연산을 추가하고자 한다면 새로운 visit() 메서드를 구현하면 됩니다.

 

 

 

 

 

반응형