방문자 패턴 (Visitor Pattern)
디자인패턴 2014. 2. 19. 15:40 |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; } |
예제 결과)