방문자 패턴

Jmnote (토론 | 기여)님의 2022년 6월 17일 (금) 17:06 판
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)

1 개요[ | ]

visitor pattern
비지터 패턴, 방문자 패턴
  • 데이터 구조를 돌아다니며 처리하는 구조
  • 알고리즘을 이 패턴을 사용하는 한 객체 구조에서 분리시키는 방법
  • 구조를 수정하지 않고 새로운 동작을 기존 객체 구조에 추가 가능
  • 개방-폐쇄 원칙에는 맞지 않는다.

2 구조[ | ]

W3sDesign Visitor Design Pattern UML.jpg

  • 왼쪽 클래스 다이어그램에서...
    • ElementA 클래스는 새로운 동작을 직접 구현하지 않는 대신, 요청을 "accept하는 비지터 객체"(visitor.visitElementA(this))로 "디스패치"하는 디스패칭 동작 accept(visitor)을 구현한다.
    • Visitor1 클래스는 실제 동작(visitElementA(e:ElementA))을 구현한다..
  • ElementB는 visitor.visitElementB(this)로 디스패치하는 accept(visitor)를 구현한다.
  • 오른쪽 시퀀스 다이어그램은 런타임 상호작용을 나타낸다.
    • Client 객체는 객체 구조의 요소들(ElementA,ElementB)을 살펴보고 각 요소에 accept(visitor)를 호출한다.
    • 우선 Client는 ElementA에 대해 accept(visitor)를 호출하는데, 이것이 다시 accpet한 visiot 객체에 대해 visitElementA(this)를 호출한다. 요소 자신(this)을 visitor에 전달하는데, 이렇게 하여 ElementA를 "방문"(operationA() 호출)하게 된다..
    • 그리고나서 Client는 ElementB에 대해 accept(visitor)를 호출하고, 이것이 다시 visitor에 대해 visitElementB(this)를 호출하며, 이것은 ElementB를 "방문"(operationB() 호출)하게 된다.

3 예제[ | ]

 

interface CarElementVisitor {
    void visit(Wheel wheel);
    void visit(Engine engine);
    void visit(Body body);
    void visit(Car car);
}
 
interface CarElement {
    void accept(CarElementVisitor visitor); // CarElements have to provide accept().
}
 
class Wheel implements CarElement {
    private String name;
 
    public Wheel(String name) {
        this.name = name;
    }
 
    public String getName() {
        return this.name;
    }
 
    public void accept(CarElementVisitor visitor) {
        /*
         * accept(CarElementVisitor) in Wheel implements
         * accept(CarElementVisitor) in CarElement, so the call
         * to accept is bound at run time. This can be considered
         * the first dispatch. However, the decision to call
         * visit(Wheel) (as opposed to visit(Engine) etc.) can be
         * made during compile time since 'this' is known at compile
         * time to be a Wheel. Moreover, each implementation of
         * CarElementVisitor implements the visit(Wheel), which is
         * another decision that is made at run time. This can be
         * considered the second dispatch.
         */ 
        visitor.visit(this);
    }
}
 
class Engine implements CarElement {
    public void accept(CarElementVisitor visitor) {
        visitor.visit(this);
    }
}
 
class Body implements CarElement {
    public void accept(CarElementVisitor visitor) {
        visitor.visit(this);
    }
}
 
class Car implements CarElement {
    CarElement[] elements;
 
    public Car() {
        //create new Array of elements
        this.elements = new CarElement[] { new Wheel("front left"), 
            new Wheel("front right"), new Wheel("back left") , 
            new Wheel("back right"), new Body(), new Engine() };
    }
 
    public void accept(CarElementVisitor visitor) {     
        for(CarElement elem : elements) {
            elem.accept(visitor);
        }
        visitor.visit(this);    
    }
}
 
class CarElementPrintVisitor implements CarElementVisitor {
    public void visit(Wheel wheel) {      
        System.out.println("Visiting " + wheel.getName() + " wheel");
    }
 
    public void visit(Engine engine) {
        System.out.println("Visiting engine");
    }
 
    public void visit(Body body) {
        System.out.println("Visiting body");
    }
 
    public void visit(Car car) {      
        System.out.println("Visiting car");
    }
}
 
class CarElementDoVisitor implements CarElementVisitor {
    public void visit(Wheel wheel) {
        System.out.println("Kicking my " + wheel.getName() + " wheel");
    }
 
    public void visit(Engine engine) {
        System.out.println("Starting my engine");
    }
 
    public void visit(Body body) {
        System.out.println("Moving my body");
    }
 
    public void visit(Car car) {
        System.out.println("Starting my car");
    }
}
 
public class VisitorDemo {
    static public void main(String[] args) {
        CarElement car = new Car();
        car.accept(new CarElementPrintVisitor());
        car.accept(new CarElementDoVisitor());
    }
}
실행결과
Visiting front left wheel
Visiting front right wheel
Visiting back left wheel
Visiting back right wheel
Visiting body
Visiting engine
Visiting car
Kicking my front left wheel
Kicking my front right wheel
Kicking my back left wheel
Kicking my back right wheel
Moving my body
Starting my engine
Starting my car

4 같이 보기[ | ]

5 참고[ | ]

문서 댓글 ({{ doc_comments.length }})
{{ comment.name }} {{ comment.created | snstime }}