본문 바로가기

JAVA/디자인 패턴

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

반응형
행위 패턴(Behavioral Pattern)


방문자 패턴(Visitor pattern)은 객체 지향 프로그래밍에서 사용되는 디자인 패턴 중 하나로, 객체의 구조와 그 구조에서 수행되는 작업을 분리하여 구현하는 패턴입니다.

방문자 패턴은 객체 구조를 이루는 요소들을 독립적으로 변경할 수 있도록 하는 패턴입니다. 즉, 객체의 구조와 구조에서 수행되는 작업을 분리하여 구현함으로써 객체의 확장성과 유연성을 높이는데 목적이 있습니다.

방문자 패턴에서는 객체 구조를 이루는 클래스들과 이들을 순회하는 방문자(visitor) 클래스를 정의합니다. 이 방문자 클래스는 객체 구조의 각 클래스를 방문하면서 그 클래스에서 수행할 작업을 구현합니다. 객체 구조에서는 방문자를 인자로 전달받아 각 클래스에서 방문자의 visit 메소드를 호출하면서 자신을 방문하도록 합니다.

이렇게 방문자 패턴을 사용하면 객체 구조를 수정하지 않고도 새로운 작업을 추가하거나 객체 구조를 순회하는 방법을 변경할 수 있습니다. 또한, 객체 구조의 요소들이 서로 다른 방문자들을 사용하여 서로 다른 작업을 수행할 수 있도록 하며, 이를 통해 객체의 유연성을 높일 수 있습니다.

예를 들어, 쇼핑몰에서 구매한 상품들의 총 가격을 계산하는 프로그램을 작성한다고 가정해보겠습니다. 이때, 쇼핑몰에는 책, 음반, 영화 등 다양한 상품이 있으며, 각각의 상품은 가격을 계산하는 방법이 다릅니다. 이때 방문자 패턴을 사용하여 상품 구조를 정의하고, 각각의 상품에서는 방문자를 받아들이고 방문자의 visit 메소드를 호출하여 가격을 계산하도록 합니다. 이렇게 하면 새로운 상품이 추가될 때마다 객체 구조를 수정하지 않고도 새로운 방문자를 추가하여 가격을 계산할 수 있습니다.

 

 

Visitor 패턴 예제

자바에서 방문자 패턴을 구현하기 위해서는 다음과 같은 요소들이 필요합니다.

  1. Element(요소) 인터페이스: 방문자가 방문할 객체들의 공통 인터페이스입니다. 이 인터페이스는 accept 메소드를 가지고 있어서, 방문자가 자신을 방문할 수 있도록 합니다.
  2. ConcreteElement(구체적인 요소) 클래스: Element 인터페이스를 구현한 클래스들입니다. 방문자가 방문할 실제 객체들입니다.
  3. Visitor(방문자) 인터페이스: Element 객체들을 방문하는 메소드들을 선언한 인터페이스입니다.
  4. ConcreteVisitor(구체적인 방문자) 클래스: Visitor 인터페이스를 구현한 클래스들입니다. Element 객체들을 방문하는 구체적인 방법들을 구현합니다.

Diagrams


먼저, 방문자(Visitor) 인터페이스를 정의합니다. 이 인터페이스는 각각의 상품 클래스에서 구현될 visit 메소드를 정의합니다.

public interface Visitor {
    int visit(Book book);
    int visit(Music music);
    int visit(Movie movie);
}



다음으로, 각각의 Element 상품 클래스(Book, Music, Movie)를 정의합니다. 각 클래스는 가격(price) 속성을 가지고 있으며, Visitor 인터페이스를 구현한 visit 메소드를 정의합니다.

public interface Element {
    int accept(Visitor visitor);
}

public class Book implements Element {
    private int price;

    public Book(int price) {
        this.price = price;
    }

    public int getPrice() {
        return price;
    }

    @Override
    public int accept(Visitor visitor) {
        return visitor.visit(this);
    }
}

public class Music implements Element {
    private int price;

    public Music(int price) {
        this.price = price;
    }

    public int getPrice() {
        return price;
    }

    @Override
    public int accept(Visitor visitor) {
        return visitor.visit(this);
    }
}

public class Movie implements Element {
    private int price;

    public Movie(int price) {
        this.price = price;
    }

    public int getPrice() {
        return price;
    }

    @Override
    public int accept(Visitor visitor) {
        return visitor.visit(this);
    }
}



마지막으로, Visitor 인터페이스를 구현한 가격 계산 Visitor 클래스를 정의합니다. 이 클래스에서는 각각의 상품을 방문하여 가격을 계산합니다.

public class PriceCalculator implements Visitor {

    @Override
    public int visit(Book book) {
        return book.getPrice();
    }

    @Override
    public int visit(Music music) {
        return music.getPrice() * 2;
    }

    @Override
    public int visit(Movie movie) {
        return movie.getPrice() * 3;
    }
}



이제 위에서 정의한 클래스들을 활용하여 간단한 예제를 작성해보겠습니다.

public class Main {
    public static void main(String[] args) {
        Element book = new Book(10000);
        Element music = new Music(5000);
        Element movie = new Movie(15000);

        Visitor visitor = new PriceCalculator();

        int totalPrice = book.accept(visitor) + music.accept(visitor) + movie.accept(visitor);

        System.out.println("Total price = " + totalPrice);
    }
}



이 예제에서는 Book, Music, Movie 클래스의 인스턴스를 생성하고, PriceCalculator 클래스의 인스턴스를 생성합니다. 각각의 상품 인스턴스에서는 accept 메소드를 호출하여 PriceCalculator 클래스의 visit 메소드를 호출합니다. 마지막으로, 각각의 가격을 더하여 총 가격을 출력합니다.

이렇게 Visitor 패턴을 사용하면, 새로운 상품이 추가될 때마다 객체 구조를 수정하지 않고도, PriceCalculator 클래스의 visit 메소드를 추가하거나 수정함으로써 가격 계산 방식을 변경할 수 있습니다.

반응형