访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式适用于数据结构相对稳定算法又易变化的系统。
这里的实现借鉴了loki,并采用C++11,可以作为参考。
这里的实现借鉴了loki,并采用C++11,可以作为参考。
namespace dp
{
struct basic_visiter
{
virtual ~basic_visiter() { }
};
template<typename R, class... Visitable> struct visiter;
template<typename R, class First, class... Other>
struct visiter<R, First, Other...> : public visiter<R, Other...>,
public visiter<R, First>
{
};
template<typename R, class Visitable>
struct visiter<R, Visitable>
{
typedef R result_type;
virtual result_type operator()(Visitable&)=0;
};
template<class R, class Visiter=basic_visiter>
struct visitable
{
typedef R result_type;
typedef Visiter visiter_type;
virtual result_type accept(visiter_type&)=0;
template<class T>
result_type accept_impl(T& visited, visiter_type& visiter)
{
typedef dp::visiter<result_type, T> visit_type;
if(visit_type* p=dynamic_cast<visit_type*>(&visiter))
{
return (*p)(visited);
}
return result_type();
}
};
}
#define DEFINE_VISITABLE_EX(result_type, visiter_type) \
virtual result_type accept(visiter_type& guest) \
{ return visitable<result_type, visiter_type>::accept_impl(*this, guest); }
#define DEFINE_VISITABLE() DEFINE_VISITABLE_EX(result_type, ::dp::basic_visiter)
#define DEFINE_VISITABLE2(result_type) DEFINE_VISITABLE_EX(result_type, ::dp::basic_visiter)
下面是个关于数值运算的例子,有两种数值类型:整数和浮点数;有两种算法:翻倍和求和。
struct MakeDouble;
struct Number : public dp::visitable<void>, public dp::visitable<double, MakeDouble>
{
DEFINE_VISITABLE2(void)
DEFINE_VISITABLE_EX(double, MakeDouble)
};
struct Int : public Number
{
DEFINE_VISITABLE2(void)
DEFINE_VISITABLE_EX(double, MakeDouble)
Int(int i) : v(i) { }
int v;
};
struct Double : public Number
{
DEFINE_VISITABLE2(void)
DEFINE_VISITABLE_EX(double, MakeDouble)
Double(double d) : v(d) { }
double v;
};
struct MakeDouble : public dp::basic_visiter,
public dp::visiter<double, Int, Double>
{
MakeDouble() { }
virtual double operator()(Double& v) { return v.v*2; }
virtual double operator()(Int& v) { return v.v*2; }
};
struct Sum : public dp::basic_visiter, public dp::visiter<void, Int, Double>
{
Sum() : m_sum(0) { }
~Sum() { cout<<"sum: "<<m_sum<<endl; }
virtual void operator()(Double& v) { m_sum+=v.v; }
virtual void operator()(Int& v) { m_sum+=v.v; }
private:
double m_sum;
};
template<typename Visiter>
void visit(std::vector<Number*>& obj, Visiter&& visiter)
{
std::for_each(obj.begin(), obj.end(), [&](Number* p) { return p->accept(visiter); } );
}
void test()
{
Int i(2);
Double d(3.14);
std::vector<Number*> obj;
obj.push_back(&i);
obj.push_back(&d);
visit(obj, MakeDouble());
visit(obj, Sum());
}
和标准的访问者模式相比,数据和算法是完全解耦的,既很容易增加新的算法,也很容易增加新的数据类型。