본문 바로가기
Programming/c++ Design Pattern

[C++ Design Pattern] Visitor

by 드가보자 2023. 12. 1.

Visitor 패턴

1 . 반복자(iteration) : 복합 객체의 모든 요소를 동일한 방식으로 열거

2 . 방문자(visitor)     : 복합 객체의 모든 요소를 동일한 방식으로 연산 수행

 

아파트 단지에 방 100개가 있다고 하자 , 얘가 반복자이다.

 

가스 검침을 수행하는 가스 검침원 (Visitor1)

가전 제품을 설치해주는 설치 기사 (Visitor2)

~~~ 기능을 하는 ~~~~~~~~~~사람 (VisitorX) 

 

이렇게 기능을 수행하는 역할들을 하나의 Class로 만들어 버리는 것이다.

 

#include <iostream>
#include <list>
#include <vector>

template<typename T>
struct IVisitor
{
	virtual void visit(T& e) = 0;
	virtual ~IVisitor(){}
};

template<typename T>
class TwiceVisitor : public IVisitor<T>
{
public:
	virtual void visit(T& e) override { e *= 2; }
};

template<typename T>
class ShowVisitor : public IVisitor<T>
{
public:
	virtual void visit(T& e) override { std::cout<<e<<std::endl; }
};

template<typename T>
class ZeroVisitor : public IVisitor<T>
{
public:
	void visit(T& e) override
	{
		e = 0;
	}
};

template<typename T>
struct IAccepter
{
	virtual void accept(IVisitor<T>* v) = 0;
	virtual ~IAccepter(){}
};

template<typename T>
class Mylist : public std::list<T>, public IAccepter<T>
{

public:

	using std::list<T>::list; // list한테 생성자를 상속

	void accept(IVisitor<T>* v) override
	{
		for (auto& e : *this)v->visit(e);
	}
};

int main()
{
	Mylist<int> s = { 1,2,3,4,5,6,7,8,9,10 };

	TwiceVisitor<int> tv;
	s.accept(&tv);

	ShowVisitor<int> sv;

	ZeroVisitor<int> zv;
	s.accept(&zv);

	s.accept(&sv);
}

 

IVisitor <= Visitor를 설계 하기 위한 Interface 

각각의 Visitor(파생 클래스)들은 IVisitor에게 상속을 받고, 하고 싶은 기능을 visit 함수를 통해서 구현을 하면 된다.

TwiceVisitor , ZeroVisitor, ShowVisitor 등 List에 있는 모든 값들에 각각의 기능 연산을 수행하는 Visitor를 만들었다.

 

이제 아파트(List)에서 visitor를 받아들일 준비를 해주면 된다.

visitor를 받겠다는 Acceptor를 만들고, Interface IAcceptor를 만들어준다. 

accept(IVisitor<T>* v) 함수를 가상 함수로 선언하고, 복합 객체에서 구현을 해준다

우린 List를 사용하고 싶으니 List와 IAcceptor에게 상속받은 Mylist를 구현한다.

 

여기서 상속을 사용하면 기반 클래스의 모든 멤버를 물려받지만, 생성자를 물려받지는 못한다. 그래서 accept함수만 재정의 해준다면 Mylist는 생성되지 않을 것인디

using std::list<T>::list; 는 list 생성자 또한 상속해줘 ! 이런 느낌입니다.  using 기반클래스이름::기반클래스생성자이름 

 

그래서 main 함수를 보면 Twicevisitor 가 for문을 돌면서 Mylsit의 값들을 모두 2배씩 시키는 것을 확인할 수 있습니다. 

 

전통적이고 일반적인 객체 지향 디자인은 

클래스의 추가는 쉽다. 다형성을 이용해서 새로 만드는 class에서 가상함수들만 잘 정의 해주면된다.

가상함수의 추가는 어렵다. Interface에 가상함수를 추가하면 수 많은 파생클래스에서 모두 재정의 해야한다.

 

==> 즉 새로운 타입을 추가하는 것은 쉬운데, operation(virtual function)의 추가는 어려운 편에 속한다.

 

방문자 패턴으로 디자인하면

=> 기능의 추가는 쉽다. Visitor 객체를 추가하면 된다. 가상함수가 해야할 일을 방문자로 설계하면 된다. 

=> 클래스의 추가는 어렵다. 

'Programming > c++ Design Pattern' 카테고리의 다른 글

[C++] Iterator  (1) 2023.12.01
[C++ Design patter] Factory.  (1) 2023.11.30
[C++ Design Pattern] Flyweight  (1) 2023.11.30
[C++ Design Pattern] Adapter  (0) 2023.11.30
[C++ Design Pattern] Decorator  (0) 2023.11.29