학습목표

  • 객체 구조(데이터)와 기능(연산)을 분리하여 설계하는 방법 이해
  • 새로운 기능을 객체 구조 변경 없이 확장하는 법을 학습
  • 타입별 다른 처리가 필요한 다형성 구조 만들기
  • 복잡한 객체 그래프(트리/컴포지트) 순회 방법 이해

활용 예제

  • 복잡한 Composite 구조에 다양한 기능을 붙여야 할 때
  • 객체 타입별 서로 다른 로직을 실행해야 할 때
  • 기존 객체 구조는 건드리기 어렵거나 변경 위험이 있을 때
  • 데이터 구조는 공통인데 ‘결과물만 다른 연산’을 추가하고 싶을 때
    • 통계 계산
    • 보고서 생성

예제

더보기

도메인 예: 문서(Document) 안에 여러 요소(Element)가 있고, 요소마다 “렌더링 방식이 다르게 동작”해야 하는 상황

  • 방문받는 객체(Element) 인터페이스
interface DocumentElement {
    void accept(DocumentVisitor visitor);
}
  • 구체 요소들 (Paragraph, Image…)
class Paragraph implements DocumentElement {
    private String text;

    public Paragraph(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }

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

class Image implements DocumentElement {
    private String url;

    public Image(String url) {
        this.url = url;
    }

    public String getUrl() {
        return url;
    }

    @Override
    public void accept(DocumentVisitor visitor) {
        visitor.visit(this);
    }
}
  • Visitor 인터페이스
interface DocumentVisitor {
    void visit(Paragraph paragraph);
    void visit(Image image);
}
  • HTML 렌더러 , 텍스트 추출기
class HtmlRenderVisitor implements DocumentVisitor {

    @Override
    public void visit(Paragraph paragraph) {
        System.out.println("<p>" + paragraph.getText() + "</p>");
    }

    @Override
    public void visit(Image image) {
        System.out.println("<img src='" + image.getUrl() + "' />");
    }
}

class TextExtractorVisitor implements DocumentVisitor {

    @Override
    public void visit(Paragraph paragraph) {
        System.out.println(paragraph.getText());
    }

    @Override
    public void visit(Image image) {
        System.out.println("[Image: " + image.getUrl() + "]");
    }
}
  • 구현
public class Main {
    public static void main(String[] args) {
        List<DocumentElement> elements = List.of(
                new Paragraph("Hello World"),
                new Image("https://example.com/image.png")
        );

        DocumentVisitor htmlVisitor = new HtmlRenderVisitor();
        DocumentVisitor textVisitor = new TextExtractorVisitor();

        System.out.println("=== HTML Render ===");
        elements.forEach(e -> e.accept(htmlVisitor));

        System.out.println("\n=== Text Extract ===");
        elements.forEach(e -> e.accept(textVisitor));
    }
}

 

- Paragraph, Image는 둘 다 같이 쓰고 방문자 구현 클래스에 따라 HTML이나 text로 표현하는 방식

 

마무리

리포트 같은 곳에서 같은 값들을 가지고 여러가지 방식으로 표현할 때 사용하기 좋아 보입니다.

+ Recent posts