已经定义了一个元素类,该类有一些成员变量。
现在希望增加一个对该类的操作。常规方法是进行派生,然后添加一个成员函数。但是这样意味着每增加一个操作,都要进行一次派生。这样随着操作数量的增加,该元素类的派生类会非常多。
于是考虑令该元素类本身固定不变,每增加一个操作,就创建一个类(访问者),该访问者类封装了对元素类的操作。当需要执行操作时,就令访问者类对象对元素类进行访问即可。
这就像吸尘器,其主体就是元素类,固定不变;不同类型的吸尘管道接口就是各种访问者。当需要吸尘器增加某个操作时,只要添加一种新的吸尘管道(访问者),然后将该管道接到吸尘器主体上(访问者访问元素类),就可以执行新的操作。该新的操作是由吸尘管道(访问者)定义的。
1. 定义元素基类及派生类
元素基类定义了一个标准接口,以接收访问者对自身的访问。这也是访问者类的访问函数Visit()被调用的地方。
// 预定义访问者类
class Visitor;
// 元素基类
class Element
{
public:
// Methods
virtual void Accept(Visitor *visitor) {};
};
// 元素派生类
class ConcreteElement : public Element
{
public:
ConcreteElement()
{
this->_attributeA = 0;
this->_attributeB = 0;
}
void Accept(Visitor *visitor)
{
visitor->Visit(this);
}
public:
int _attributeA;
int _attributeB;
};
2. 定义访问者基类及派生类
访问者基类定义了一个标准接口,以对元素基类进行访问。
每添加一种操作,就派生一个具体访问者类。具体访问者在访问函数中将传入的元素基类指针转换为具体元素类指针,并进行操作。不同访问者的差异就在于该访问函数的实现。
// 访问者基类
class Visitor
{
public:
virtual void Visit(Element *element) {};
};
// 具体访问者A
class ConcreteVisitorA : public Visitor
{
public:
void Visit(Element *element)
{
ConcreteElement *concreteElement = ((ConcreteElement*)element);
//修改属性ConcreteElement::_attributeA
concreteElement->_attributeA = 65;
}
};
// 具体访问者B
class ConcreteVisitorB : public Visitor
{
public:
void Visit(Element *element)
{
ConcreteElement *concreteElement = ((ConcreteElement*)element);
//修改属性ConcreteElement::_attributeB
concreteElement->_attributeB = 66;
}
};
3. 定义结构对象
结构对象用于对所有的具体元素对象进行保存。
当有访问者时,访问者会访问所有的元素,于是在结构对象中添加一个对所有元素进行访问的接口。
// 结构对象
class ObiectStructure
{
public:
void Attach(ConcreteElement *concreteElement)
{
concreteElements.push_back(concreteElement);
}
void Detach(ConcreteElement *concreteElement)
{
concreteElements.remove(concreteElement);
}
void Accept(Visitor *visitor)
{
// 令每个元素都接受一次访问
for (std::list<ConcreteElement*>::iterator it = concreteElements.begin(); it != concreteElements.end(); ++it)
(*it)->Accept(visitor);
}
private:
list< ConcreteElement*> concreteElements;
};
4. 用户使用
用户需要维护一个结构对象,并将所有的具体元素添加到该对象中。
创建不同的具体访问者,然后令所有元素接受该访问。
void main()
{
ObiectStructure *obiectStructure = new ObiectStructure();
obiectStructure->Attach(new ConcreteElement());
obiectStructure->Attach(new ConcreteElement());
obiectStructure->Attach(new ConcreteElement());
// 创建两个访问者
ConcreteVisitorA *v1 = new ConcreteVisitorA();
ConcreteVisitorB *v2 = new ConcreteVisitorB();
// 结构对象接受访问者的访问
obiectStructure->Accept(v1);
obiectStructure->Accept(v2);
}