Thinking Different






Visitor Pattern - 방문자 패턴


  • 객체의 구조와 기능을 분리시키는 패턴
  • 구조는 변하지 않으며 기능만을 따로 추가되거나 확장되어야 할 경우에 사용되는 패턴이다.
  • 컴포지트 패턴(Composite Pattern)과 연동되어 사용되는 경우가 많다.







샘플 코드)

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
//------------------------------------------------------------------
// Visitor 인터페이스
class Element;
class Visitor
{
public:
    virtual void visitElementA(Element* e) = 0;
    virtual void visitElementB(Element* e) = 0;
};
 
//------------------------------------------------------------------
// Element 인터페이스
class Element
{
public:
    virtual void accept(Visitor* v) = 0;
};
 
//------------------------------------------------------------------
// ConcreteElementA 상속 클래스
class ConcreteElementA : public Element
{
public:
    void accept(Visitor* v) override { v->visitElementA(this); }
};
 
//------------------------------------------------------------------
// ConcreteElementB 상속 클래스
class ConcreteElementB : public Element
{
public:
    void accept(Visitor* v) override { v->visitElementB(this); }
};
 
//------------------------------------------------------------------
// ConcreteVisitor 상속 클래스
class ConcreteVisitor : public Visitor
{
public:
    void visitElementA(Element* e) { cout << "visitElementA" << endl; }
    void visitElementB(Element* e) { cout << "visitElementB" << endl; }
};
 
//------------------------------------------------------------------
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    ConcreteElementA mConcreteElementA;
    ConcreteElementB mConcreteElementB;
 
    ConcreteVisitor mConcreteVisitor;
 
    mConcreteElementA.accept(&mConcreteVisitor);
    mConcreteElementB.accept(&mConcreteVisitor);
 
    return 0;
}





예제를 통한 비지터 패턴(Visitor Pattern) 알아보기



예제) 자동차 기능에 따른 비지터 패턴 예제



각각의 자동차 파트(Wheel, Body, Engine)이 존재하고 컴포지트 패턴을 활동한 Car 클래스를 구현했다. Car 클래스에서는 각각의 파트 Element를 추가하여 accept 메서드를 호출하여 visitor 패턴을 호출하는 예제이다.

visitor 클래스는 각각 자동차를 구동하는 기능 클래스인 CarStartVisitor와 자동차 상태를 점검하는 클래스인 CarPrintVisitor가 구현되었으며, 각각의 Element에 따라서 visit 메서드로 구현하였다.



예제 코드)

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <list>
 
#if _UNICODE
typedef wstring tstring;
#else
typedef string tstring;
#endif
 
//------------------------------------------------------------------
// Element 인터페이스
class Visitor;
class Element
{
public:
    virtual void accept(Visitor* v) = 0;
};
 
//------------------------------------------------------------------
// Wheel 상속 클래스
class Wheel : public Element
{
public:
    Wheel(const TCHAR* name) : mName(name) {}
 
public:
    void accept(Visitor* v) override;
    const TCHAR* getName() const { return mName.c_str(); }
 
private:
    tstring mName;
};
 
//------------------------------------------------------------------
// Engine 상속 클래스
class Engine : public Element
{
public:
    void accept(Visitor* v) override;
};
 
//------------------------------------------------------------------
// Body 상속 클래스
class Body : public Element
{
public:
    void accept(Visitor* v) override;
};
 
//------------------------------------------------------------------
// Car 상속 클래스 (컴포지트 패턴)
class Car : public Element 
{
public:
    void append(Element* e) { mList.push_back(e); }
    void accept(Visitor* v) override;
 
private:
    list<Element*> mList;
};
 
//------------------------------------------------------------------
// Visitor 인터페이스
class Visitor
{
public:
    virtual void visit(Wheel* e) = 0;
    virtual void visit(Engine* e) = 0;
    virtual void visit(Body* e) = 0;
    virtual void visit(Car* e) = 0;
};
 
//------------------------------------------------------------------
// CarPrintVisitor 상속 클래스
class CarPrintVisitor : public Visitor
{
public:
    void visit(Wheel* e) override { cout << "Visiting " << e->getName() << " Wheel" << endl; }
    void visit(Engine* e) override { cout << "Visiting engine" << endl; }
    void visit(Body* e) override { cout << "Visiting body" << endl; }
    void visit(Car* e) override { cout << "Visiting car" << endl; }
};
 
//------------------------------------------------------------------
// CarStartVisitor 상속 클래스
class CarStartVisitor : public Visitor
{
public:
    void visit(Wheel* e) override { cout << "Kicking my " << e->getName() << " Wheel" << endl; }
    void visit(Engine* e) override { cout << "Starting my engine" << endl; }
    void visit(Body* e) override { cout << "Moving my body" << endl; }
    void visit(Car* e) override { cout << "Starting my car" << endl; }
};
 
//------------------------------------------------------------------
// 전방 선언에 따른 하단 구현
void Wheel::accept(Visitor* v) { v->visit(this); }
void Engine::accept(Visitor* v) { v->visit(this); }
void Body::accept(Visitor* v) { v->visit(this); }
void Car::accept(Visitor* v) { for (auto i = mList.begin(); i != mList.end(); ++i) (*i)->accept(v); v->visit(this); }
 
//------------------------------------------------------------------
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    // 부품 생성
    Wheel mWheel[4] = { "front left""front right""back left""back right" };
    Engine mEngine;
    Body mBody;
    Car mCar;
 
    // 파트 추가
    mCar.append(&mWheel[0]);
    mCar.append(&mWheel[1]);
    mCar.append(&mWheel[2]);
    mCar.append(&mWheel[3]);
    mCar.append(&mEngine);
    mCar.append(&mBody);
 
    // visitor 생성
    CarPrintVisitor mCarPrintVisitor;
    CarStartVisitor mCarStartVisitor;
 
    // visitor accept 처리
    mCar.accept(&mCarPrintVisitor);
    mCar.accept(&mCarStartVisitor);
 
    return 0;
}


예제 결과)