자바 디자인 패턴 용어 사전
행위 패턴방문자

Visitor

객체 구조는 그대로 두고 연산만 외부 클래스로 분리하는 패턴. 더블 디스패치를 쓴다.

객체 구조는 그대로 두고 연산만 밖으로 빼는 패턴.

interface Visitor {
    void visit(Circle c);
    void visit(Square s);      // 요소 종류마다 메서드
}

interface Shape { void accept(Visitor v); }
class Circle implements Shape {
    public void accept(Visitor v) { v.visit(this); }   // ← 더블 디스패치
}

// 새 연산은 Visitor 구현만 추가하면 된다 — Shape 는 안 건드린다
class AreaCalculator implements Visitor { ... }
class XmlExporter implements Visitor { ... }

더블 디스패치가 핵심이다

자바는 단일 디스패치다 — 오버로딩은 '컴파일 시점 정적 타입' 으로 정해진다

  • void render(Shape s) { visitor.visit(s); } // ✗ 항상 visit(Shape) 가 불린다
Visitor 는 두 번 위임해 이를 우회한다
  ① shape.accept(visitor)   → 실제 타입(Circle) 의 accept 가 불린다 (동적)
  ② v.visit(this)           → this 의 정적 타입이 Circle 이라 visit(Circle) 선택

두 번 거쳐야 '실제 타입에 맞는 연산' 에 도달한다

확장의 방향이 반대다

연산 추가가 쉽다새 Visitor 클래스 하나
요소 추가가 어렵다Visitor 인터페이스와 모든 구현 수정
  • 일반적인 OOP 는 반대다 (요소 추가가 쉽고 연산 추가가 어렵다)
  • 이것이 '표현 문제(expression problem)' 다

그래서 요소 종류가 안정적이고 연산이 자주 느는 경우에만 쓴다

  • 예) 컴파일러 AST — 노드 종류는 고정, 연산(타입검사·최적화·생성)은 계속 는다

자바에서는 대안이 생겼다

// sealed + 패턴 매칭 switch — 완전성을 컴파일러가 검사한다
String describe(Shape s) {
    return switch (s) {
        case Circle c -> "원 " + c.r();
        case Square q -> "사각 " + q.side();
    };   // 새 하위 타입이 생기면 컴파일 오류로 잡힌다
}

Visitor의 보일러플레이트 없이 같은 효과를 낸다. 모던 자바에서는 이쪽이 더 흔한 선택이다.

면접 함정

  • "요소 추가가 쉽다" → 반대다. 연산 추가가 쉽고 요소 추가가 어렵다.
  • 더블 디스패치를 설명 못 함 → 이 패턴의 존재 이유가 그것이다.

왜 accept가 필요한가

// accept 없이 하려면 instanceof 분기가 필요하다
void visit(Shape s) {
    if (s instanceof Circle c) ...
    else if (s instanceof Square q) ...   // 요소가 늘 때마다 여기를 고친다
}

s.accept(visitor);   // 가상 함수 호출로 대체 — JVM 이 실제 타입에 맞게 부른다

상태를 들고 다닐 수 있다

class TotalAreaVisitor implements Visitor {
    private double total;
    public void visit(Circle c) { total += Math.PI * c.r() * c.r(); }
    double result() { return total; }
}

연산 상태와 타입별 처리를 한 클래스에 모은다는 점이 외부 반복자와 다르다.

요소 추가가 어렵다는 것의 실제 의미

Shape 에 Triangle 을 추가하면

  • Visitor 인터페이스에 visit(Triangle) 추가
  • 기존 Visitor 구현 전부에 메서드 추가 (컴파일 오류로 강제된다)

구현이 10개면 10곳을 고친다 — 요소가 안정적일 때만 쓰는 이유다

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 행위 패턴 ③ — 알고리즘과 상태를 갈아 끼운다