방문자 패턴이란?
알고리즘을 객체 구조에서 분리시키는 디자인 패턴(행위 패턴)
구조를 수정하지 않고 새로운 동작을 기존 객체에 추가할 수 있다.
(연산을 적용할 객체의 클래스를 변경하지 않고도 새로운 연산을 정의할 수 있다.)
클래스에서 객체를 다루는 기능을 내부 메소드로 구현하는 것이 아닌, 각 클래스들의 데이터 구조에서 처리 기능을 분리하여 별도의 클래스로 구현하는 패턴이다.
분리된 처리 기능은 Visitor를 통해 각 클래스들을 방문하면서 수행한다.
즉, 실제 로직을 가지고 있는 객체가 로직을 적용할 객체를 방문하면서 실행하는 패턴이다. (로직과 구조를 분리하는 패턴)
※ 비지터 객체는 Traverser 객체와 함께 돌아간다.
- 트래버서는 컴포지트 패턴을 쓸 때, 복합 객체 내에 속해 있는 모든 객체에 접근하는 일을 도와주는 역할을 한다.
- 비지터 객체에서 복합 객체 내의 모든 객체를 대상으로 원하는 작업을 처리하게 해준다.
- 각각의 상태를 모두 가져오면 클라이언트는 비지터에게 각 상태에 맞는 다양한 작업을 처리하도록 요구할 수 있다.
- 새로운 기능이 필요하게 되더라도 비지터만 고치면 되기에 편리하다.
장점
- 구조를 변경하지 않으면서도 복합 객체 구조에 새로운 기능을 추가할 수 있다.
- 비지터가 수행하는 기능과 관련된 코드를 한곳에 모아둘 수 있다.
단점
- 새로운 작업 대상이 추가될 때마다 방문자 로직을 추가해야 한다.
- 방문자와 작업 대상의 결합도가 높아진다.
IVisitor
- 방문자 인터페이스로 visit(Element) 메소드를 공용 인터페이스로 사용. (Element = 작업 대상)
IElement
- 작업 대상 클래스의 인터페이스로 accept(Visitor) 메소드를 공용 인터페이스로 사용. (Visitor = 방문자)
- 내부적으로 Visitor.visit(this)를 호출한다.
적용 상황
- 데이터와 알고리즘을 분리할 때. (코드의 응집도를 높이고자 할 때)
- 데이터 구조보다 알고리즘이 더 자주 바뀔 때.
- 적용해야 할 대상 객체가 잘 바뀌지 않을 때. ※ 특히 개수
- 적용할 알고리즘이 추가될 가능성이 많은 상황일 때.
사용예시
IVisitor Interface
public interface IVisitor {
public void visit(IElement element);
}
VisitorA Class
public class VisitorA implements IVisitor {
@Override
public void visit(IElement element) {
if(element instanceof ElementA) {
System.out.println("VisitorA : " + element.getClass());
} //
else {
System.out.println("element는 ElementA 객체가 아닙니다.");
}
}
}
VisitorB Class
public class VisitorB implements IVisitor {
@Override
public void visit(IElement element) {
if(element instanceof ElementB) {
System.out.println("VisitorB : " + element.getClass());
} //
else {
System.out.println("element는 ElementB 객체가 아닙니다.");
}
}
}
IElement Interface
public interface IElement {
public void accept(IVisitor visitor);
}
ElementA Class
public class ElementA implements IElement {
@Override
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}
ElementB Class
public class ElementB implements IElement {
@Override
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}
Main Class
public class Main {
public static void main(String[] args) {
IElement elementA = new ElementA();
IElement elementB = new ElementB();
elementA.accept(new VisitorA());
elementB.accept(new VisitorB());
elementA.accept(new VisitorB());
elementB.accept(new VisitorA());
}
}
메소드를 통해 기능을 수행하는 것이 아닌 기능을 수행하는 클래스에서 객체를 넘겨 받아 기능을 수행한다.
(기능을 클래스로 따로 구현)
'CS > 디자인 패턴' 카테고리의 다른 글
Facade Pattern 퍼사드 패턴 (0) | 2022.10.12 |
---|