디자인 패턴

Visitor Pattern

kyoulho 2025. 3. 3. 16:19
728x90

"데이터 구조는 그대로, 기능만 확장하고 싶을 때!"

  • 방문자 패턴은 객체 구조를 변경하지 않고 기능을 추가할 수 있는 강력한 패턴입니다.
  • 특히 데이터 구조는 안정적이고 기능이 자주 추가되는 경우에 적합합니다.
  • 하지만 새로운 데이터 구조를 추가하는 경우 유지보수가 어려울 수 있음을 고려해야 합니다.

📌 방문자 패턴의 핵심 개념

  1. Visitor (방문자)
    • 객체의 데이터 구조를 변경하지 않고 새로운 기능을 추가하는 역할
    • 객체의 내부 구조를 알 필요 없이, 방문한 객체의 accept() 메서드를 통해 적절한 동작을 수행함
  2. Element (요소, 데이터 구조)
    • 방문자의 기능을 수락하는 역할 (accept(visitor))
    • 각 요소는 Visitor 인터페이스를 구현한 객체를 받아서 적절한 방문자를 실행함
  3. ConcreteVisitor (구체적인 방문자)
    • 실제로 각 Element를 방문하여 특정 동작을 수행하는 클래스
    • 여러 개의 ConcreteVisitor를 만들어 다양한 기능을 추가 가능
  4. ConcreteElement (구체적인 요소)
    • Element를 구현한 클래스
    • accept(visitor)를 통해 방문자를 받아들이고, 방문자의 메서드를 호출하여 기능을 실행함

📌 방문자 패턴의 동작 방식

  1. Element는 accept(visitor: Visitor) 메서드를 제공하여 방문자를 받음.
  2. Visitor는 visit(elementA: ElementA)와 같은 방문 메서드를 제공.
  3. ConcreteElement는 accept(visitor) 메서드에서 visitor.visit(this)를 호출하여 방문자에게 자신을 넘김.
  4. ConcreteVisitor는 visit() 메서드를 통해 특정 요소에 대한 동작을 수행.

📌 방문자 패턴의 UML

      +----------------+
      |   IElement     |<----------------------+
      |  + accept()    |                       |
      +----------------+                       |
           ▲                                   |
           |                                   |
   +----------------+         +----------------+
   | ElementA       |         | ElementB       |
   | + accept()     |         | + accept()     |
   +----------------+         +----------------+
           ▲                                   ▲
           |                                   |
 +------------------+       +------------------+
 | Visitor         |        | ConcreteVisitor  |
 | + visit(A)      |        | + visit(A)       |
 | + visit(B)      |        | + visit(B)       |
 +------------------+       +------------------+

📌 예제 코드 (Java)

// 1. Visitor 인터페이스
interface Visitor {
    void visit(Book book);
    void visit(Food food);
}

// 2. Element 인터페이스
interface Element {
    void accept(Visitor visitor);
}

// 3. ConcreteElement 클래스
class Book implements Element {
    String title;

    public Book(String title) {
        this.title = title;
    }

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

class Food implements Element {
    String name;

    public Food(String name) {
        this.name = name;
    }

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

// 4. ConcreteVisitor 클래스
class DiscountVisitor implements Visitor {
    @Override
    public void visit(Book book) {
        System.out.println("책 \"" + book.title + "\"에 할인을 적용합니다.");
    }

    @Override
    public void visit(Food food) {
        System.out.println("음식 \"" + food.name + "\"에 할인을 적용합니다.");
    }
}

// 5. 사용 예시
public class VisitorPatternExample {
    public static void main(String[] args) {
        Element[] items = { new Book("자바 디자인 패턴"), new Food("라면") };
        Visitor discountVisitor = new DiscountVisitor();

        for (Element item : items) {
            item.accept(discountVisitor);
        }
    }
}

출력 결과:

책 "자바 디자인 패턴"에 할인을 적용합니다.
음식 "라면"에 할인을 적용합니다.

📌 방문자 패턴의 장단점

장점

  1. 새로운 기능을 쉽게 추가할 수 있음
    • 기존 데이터 구조(Element)를 수정하지 않고 새로운 기능(Visitor)을 추가 가능
  2. 객체 구조를 유지하면서 다양한 연산을 적용 가능
    • 데이터 구조(Element)는 변경되지 않으므로 기존 시스템에 영향을 주지 않음
  3. OCP(Open-Closed Principle) 준수
    • 요소 클래스(Element)는 수정할 필요 없이 확장이 가능

단점

  1. 데이터 구조가 자주 변경되는 경우 적합하지 않음
    • 새로운 요소(Element)가 추가되면 모든 방문자(Visitor)를 수정해야 함
  2. 객체 구조가 복잡해질 수 있음
    • 방문자 패턴을 적용할 경우, 요소와 방문자가 분리되어 코드가 복잡해질 수 있음

📌 방문자 패턴을 사용해야 할 때

적합한 경우

  • 데이터 구조(Element)는 안정적이고, 기능(Visitor)이 자주 변경되는 경우
  • 다양한 연산(통계 처리, 보고서 생성 등)을 객체에 적용해야 하는 경우
  • 데이터 구조를 유지하면서, 새로운 동작을 추가해야 하는 경우

적합하지 않은 경우

  • 데이터 구조(Element) 자체가 자주 변경되는 경우 (Visitor 패턴이 비효율적)
  • 방문자 패턴을 적용하기 어려울 정도로 구조가 간단한 경우

📌 방문자 패턴이 사용되는 예시

  • 컴파일러
    • AST(Abstract Syntax Tree) 노드를 방문하여 코드 분석, 최적화, 코드 생성 수행
  • XML/JSON 파서
    • XML/JSON 문서의 각 노드를 방문하여 변환 또는 검증 수행
  • 파일 시스템 탐색기
    • 디렉토리 및 파일을 방문하여 특정 작업(예: 용량 계산, 보안 검사 등) 수행

 

728x90

'디자인 패턴' 카테고리의 다른 글

template method pattern  (0) 2024.07.05
State Pattern  (0) 2024.06.15
Singletone Pattern  (0) 2024.06.15
Proxy Pattern  (0) 2024.06.15
Observer Pattern  (0) 2024.05.30