Featured image of post 14. 다양한 패턴 빠르게 알아보기 - 비지터 패턴

14. 다양한 패턴 빠르게 알아보기 - 비지터 패턴

헤드 퍼스트 디자인 패턴

비지터(Visitor) 패턴

다양한 객체에 새로운 기능을 추가해야 하는데 캡슐화가 별로 중요하지 않다면 비지터 패턴을 쓴다.

비지터 패턴은 객체 구조를 정의하고, 이 구조를 기반으로 알고리즘을 캡슐화하여 새로운 알고리즘을 추가할 때 기존 코드를 수정하지 않고 확장하는 디자인 패턴 중 하나이다.

주로 데이터 구조와 처리를 분리하여 새로운 처리를 쉽게 추가하고 확장할 수 있도록 한다.

특징

  • 알고리즘 분리
    • 알고리즘을 객체 구조에서 분리하여 캡슐화하고, 각 알고리즘을 방문자(Visitor)로 정의한다.
  • 확장성 향상
    • 새로운 알고리즘을 추가할 때 기존 코드를 수정하지 않고 확장할 수 있다.

구조

비지터 패턴 구조

  • Visitor(방문자)
    • 객체 구조를 방문하여 각 구조에 대한 알고리즘을 수행하는 인터페이스를 정의한다.
  • ConcreteVisitor
    • Visitor 인터페이스를 구현하고, 실제 알고리즘을 구현한다.
  • Element(요소)
    • 방문자가 방문하는 객체의 언터페이스를 정의한다.
  • ConcreteElement
    • Element 인터페이스를 구현하고, 방문자의 방문을 받아들이는 메서드를 구현한다.
  • ObjectStructure(객체 구조)
    • 여러 요소를 포함하는 객체 구조를 정의하고, 방문자를 받아들이는 메서드를 제공한다.

예시

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// Visitor
public interface Visitor {
    void visit(ConcreteElementA element);
    void visit(ConcreteElementB element);
}

// ConcreteVisitor
public class ConcreteVisitor implements Visitor {
    @Override
    public void visit(ConcreteElementA element) {
        System.out.println("Visit ConcreteElementA");
    }

    @Override
    public void visit(ConcreteElementB element) {
        System.out.println("Visit ConcreteElementB");
    }
}

// Element
public interface Element {
    void accept(Visitor visitor);
}

// ConcreteElement
public class ConcreteElementA implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

// ConcreteElement
public class ConcreteElementB implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

// ObjectStructure
public class ObjectStructure {
    private List<Element> elements = new ArrayList<>();

    public void addElement(Element element) {
        elements.add(element);
    }

    public void accept(Visitor visitor) {
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

// Client
public class Client {
    public static void main(String[] args) {
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.addElement(new ConcreteElementA());
        objectStructure.addElement(new ConcreteElementB());

        Visitor visitor = new ConcreteVisitor();
        objectStructure.accept(visitor);
    }
}

장단점

장점

  • 알고리즘 추가의 용이성
    • 새로운 알고리즘을 추가하거나 기존 알고리즘을 수정할 때, 기존 코드를 건드리지 않고 확장할 수 있다.
    • 비교적 손쉽게 새로운 기능을 추가할 수 있다.
  • 구조와 알고리즘의 분리
    • 비지터가 수행하는 기능과 관련된 코드를 한곳에 모아 둘 수 있다.
    • 객체 구조와 알고리즘을 분리하여 코드를 보다 모듈화하고 유지보수성을 높일 수 있다.

단점

  • 캡슐화 불가능
    • 비지터를 사용하면 복합 클래스의 캡슐화가 깨진다.
  • 구조 변경 어려움
    • 컬렉션 내의 모든 항목에 접근하는 트래버서(클라이언트)가 있으므로 복합 구조를 변경하기가 더 어려워진다.
  • 클래스 증가
    • 새로운 요소나 알고리즘을 추가할 때마다 클래스의 수가 늘어난다.
    • 이로 인해 클래스의 수가 많아지면 유지보수가 어려워질 수 있다.