Java

[Design Pattern] 방문자 패턴(Visitor Pattern)

구루싸 2020. 7. 9. 22:30
반응형
SMALL

이번 학습 주제는

방문자 패턴(Visitor Patter)입니다

방문자 패턴은

방문자를 나타내는 클래스를 준비하고

이 클래스에게 처리를 위임함으로써

데이터 구조와 처리를 분리합니다

먼저 방문자 패턴의 역할들을

정리하고 시작하겠습니다

역할 설명
Visitor(방문자) 데이터 구조의 전체적인 요소마다 visit 메소드 선언
Concrete Visitor(구체적인 방문자) Visitor 역할의 인터페이스를 구현
Element(요소) Visitor 역할이 방문할 곳을 나타내는 역할로 방문자를 받아들이는 accept 메소드 선언
Concrete Element(구체적인 요소) Element 역할의 인터페이스를 구현
Object Structure(오브젝트 구조) Element 역할의 집합을 취급하는 역할

이제 구현을 하겠습니다

지난 디자인 패턴 학습 중에

Composite Pattern 내용을

조금 수정하는 것으로 될 것 같네요

Composite Pattern이 궁금하시다면

아래의 링크 ↓

2020/07/05 - [Java] - [Design Pattern] 복합체 패턴(Composite Pattern)

 

[Design Pattern] 복합체 패턴(Composite Pattern)

어느 덧 7월 2020년도 하반기로 접어들었습니다 남은 반년 화이팅하시고 좋은 성과와 행복이 가득하시길 기원합니다 아무튼 오늘의 학습 주제는 복합체 패턴입니다 컴퓨터 파일 시스템(File System)

yssa.tistory.com

1. 추상 클래스(Abstract Class) Visitor.java

package visitorPattern;

public abstract class Visitor {
	public abstract void visit(File file);
	public abstract void visit(Directory directory);
}

2. 클래스(Class) ListVisitor.java

package visitorPattern;
import java.util.*;
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<Entry> it = directory.iterator();
		while ( it.hasNext() ) {
			Entry entry = (Entry) it.next();
			entry.accept(this);
		}
		currentDir = saveDir;
	}
}

3. 인터페이스(Interface) Element.java

package visitorPattern;

public interface Element {
	public abstract void accept(Visitor v);
}

4. 추상 클래스(Abstract Class) Entry.java

package visitorPattern;
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<Entry> iterator() throws FileTreatmentException {
		throw new FileTreatmentException();
	}
	public String toString() {
		return getName() + " (" + getSize() + ")";
	}
}

5. 클래스(Class) Directory.java

package visitorPattern;
import java.util.*;
public class Directory extends Entry {
	private String name;
	private ArrayList<Entry> directory = new ArrayList<Entry>();
	public Directory(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public int getSize() {
		int size = 0;
		Iterator<Entry> it = directory.iterator();
		while ( it.hasNext() ) {
			Entry entry = (Entry) it.next();
			size += entry.getSize();
		}
		return size;
	}
	public Entry add(Entry entry) {
		directory.add(entry);
		return this;
	}
	public Iterator<Entry> iterator() {
		return directory.iterator();
	}
	public void accept(Visitor v) {
		v.visit(this);
	}
}

6. 클래스(Class) File.java

package visitorPattern;

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);
	}
}

7. 클래스(Class) FileTreatmentException.java

package visitorPattern;

public class FileTreatmentException extends RuntimeException {
	public FileTreatmentException() {
	}
	public FileTreatmentException(String msg) {
		super(msg);
	}
}

8. 클래스(Class) Test.java

import visitorPattern.*;
public class Test {
	public static void main(String[] args) {
		/* Visitor Pattern */
		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");
			Directory Sa = new Directory("Sa");
			usrDir.add(Kim);
			usrDir.add(Lee);
			usrDir.add(Park);
			usrDir.add(Sa);
			Kim.add(new File("diary.html", 100));
			Lee.add(new File("memo.txt", 200));
			Park.add(new File("game.c", 300));
			Sa.add(new File("Composite.java", 400));
			rootDir.accept(new ListVisitor());
		} catch ( FileTreatmentException e ) {
			e.printStackTrace();
		}
	}
}

위의 코드를 보시면

Visitor 패턴에서는

Concrete Element, Concrete Visitor 

한쌍에 의해 실제 처리가 결정됩니다

이런 것을 더블 디스패치(Double Dispatch)라고 합니다

그런데 너무 복잡해보이네요-_-

앞에서도 언급했지만

Visitor 패턴의 주요 목적이

처리를 데이터 구조로부터 분리하는 것인데

이렇게 함으로써 목적을 달성합니다

참고 ☞ The Open-Closed Principle(OCP) 원칙

이번 주제는 이해하기 다소 어려웠는데

Concrete Visitor를 추가하거나

Concrete Element를 추가해보면서

좀 더 학습해봐야겠습니다

아무튼 오늘의 학습은

이것으로 마치겠습니다

그럼 이만-_-

반응형
LIST