Visitor パターン

Visitor パターン - Wikipedia

データ構造(Element)と処理(Visitor)の分離を実現。これにCompositeパターンを組み合わせると面白い。
ConcreteVisitorの追加は容易な一方、ConcreteElementの追加は難しい。

ダブルディスパッチ - Wikipediaも関係があるので合わせて読むとよい。

以下の例はwikipediaに載っていたC++のコードをちょいちょいといじったもの。

#include <iostream>
#include <vector>
using namespace std;
//Concrete Elements
class Wheel;
class Engine;
class Body;
class Car;
//Visitor
class Visitor
{
public:
	Visitor(){}
	virtual ~Visitor(){}
	virtual void Visit(Wheel &) = 0;
	virtual void Visit(Engine &) = 0;
	virtual void Visit(Body &) = 0;
	virtual void Visit(Car &) = 0;
};
//Concret Visitor
class TestVisitor : public Visitor
{
public:
	TestVisitor(){}
	virtual ~TestVisitor(){}
	virtual void Visit(Wheel & wheel){
		cout << "Visiting Wheel" << endl;
	}
	virtual void Visit(Engine & engine){
		cout << "Visiting Engine" << endl;
	}
	virtual void Visit(Body & body){
		cout << "Visiting Body" << endl;
	}
	virtual void Visit(Car & car){
		cout << "Visiting Car" << endl;
	}
};
//Element
class CarElement
{
public:
	CarElement(){}
	virtual ~CarElement(){}
	virtual void Accept(Visitor &) = 0;
};
//Concrete Element 1
class Wheel : public CarElement
{
public:
	virtual void Accept(Visitor & visitor) {
		visitor.Visit(*this);
	}
};
//Concrete Element 2
class Engine : public CarElement
{
public:
	virtual void Accept(Visitor & visitor) {
		visitor.Visit(*this);
	}
};
//Concrete Element 3
class Body : public CarElement
{
public:
	Body(int size){
		for(int i = 0; i < size; i++){
			wheels_.push_back(new Wheel);
		}
	}
	~Body(){
		for(vector<Wheel*>::iterator itr = wheels_.begin(); itr != wheels_.end(); itr++){
			delete (*itr);
		}
	}
	virtual void Accept(Visitor & visitor) {
		visitor.Visit(*this);

		for (vector<Wheel*>::iterator itr = wheels_.begin(); itr != wheels_.end(); itr++) {
			(*itr)->Accept(visitor);
		}
	}
private:
	vector<Wheel*> wheels_;
};
//Concrete Element 4
class Car : public CarElement {
public:
	Car(){
		engine_ = new Engine();
		body_ = new Body(4);
	}
	~Car(){
		delete engine_;
		delete body_;
	}
	virtual void Accept(Visitor & visitor) {
		visitor.Visit(*this);
		engine_->Accept(visitor);
		body_->Accept(visitor);
	}
private:
	Engine *engine_;
	Body *body_;
};
//main
int main()
{
	Car car;
	TestVisitor visitor;
	car.Accept(visitor);
}