代码框架
- 定义访问者接口
class Visitor {
public:
virtual void visitElement1(Element1* element) = 0;
virtual void visitElement2(Element2* element) = 0;
// 其他具体元素的访问方法
};
- 定义元素基类和具体元素类
class Element {
public:
virtual void accept(Visitor* visitor) = 0;
};
class Element1 : public Element {
private:
int privateData1;
public:
Element1(int data) : privateData1(data) {}
void accept(Visitor* visitor) override {
visitor->visitElement1(this);
}
// 提供获取私有成员的方法(仅为示例,实际可按需调整)
int getPrivateData1() {
return privateData1;
}
};
class Element2 : public Element {
private:
double privateData2;
public:
Element2(double data) : privateData2(data) {}
void accept(Visitor* visitor) override {
visitor->visitElement2(this);
}
// 提供获取私有成员的方法(仅为示例,实际可按需调整)
double getPrivateData2() {
return privateData2;
}
};
- 定义具体访问者类
class ConcreteVisitor : public Visitor {
public:
void visitElement1(Element1* element) override {
int data = element->getPrivateData1();
// 处理数据
}
void visitElement2(Element2* element) override {
double data = element->getPrivateData2();
// 处理数据
}
};
- 使用访问者模式
int main() {
Element1* element1 = new Element1(10);
Element2* element2 = new Element2(3.14);
Visitor* visitor = new ConcreteVisitor();
element1->accept(visitor);
element2->accept(visitor);
delete element1;
delete element2;
delete visitor;
return 0;
}
优势
- 分离数据操作和数据结构:访问者模式将对数据的操作从数据结构中分离出来,使得数据结构和操作可以独立变化。例如,当需要对
Element
及其子类的私有成员进行新的操作时,不需要修改Element
类及其子类的代码,只需添加新的访问者类。
- 增加新操作的灵活性:方便在不改变现有类层次结构的情况下,增加新的操作。如果没有访问者模式,每次添加新操作都可能需要修改
Element
类及其子类,违反开闭原则。
- 集中相关操作:将相关的操作集中在访问者类中,使代码结构更清晰,更易于维护和理解。
适用场景
- 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类型的操作:比如
Element
类及其多个子类,不同子类有不同的私有成员,希望对不同子类的私有成员执行不同操作。
- 需要对一个对象结构中的对象进行很多不同且不相关的操作,而你想避免让这些操作“污染”这些对象的类:将操作封装在访问者类中,保持对象类的简洁。
- 当对象结构的类很少改变,但经常需要在此结构上定义新的操作时:因为使用访问者模式可以在不修改对象结构类的前提下添加新操作。