新增访问者指的是新增继承Visitor的子类
下面给出访问者模式(Visitor Pattern)的几个好处,每个好处附带一个示例及相应的
代码。
- 增加新的操作更容易
【好处说明】
在不修改现有元素类的前提下,可通过新增访问者类来扩展新的功能。例如,给图形对象增加计算面积的操作。
#include <iostream>
#include <vector>
// 前向声明
class Circle;
class Rectangle;
// Visitor 接口
class Visitor {
public:
virtual void Visit(Circle* circle) = 0;
virtual void Visit(Rectangle* rectangle) = 0;
};
// Element 接口
class Shape {
public:
virtual void Accept(Visitor* visitor) = 0;
};
// Element 子类 Circle
class Circle : public Shape {
public:
double radius;
Circle(double r) : radius(r) {}
void Accept(Visitor* visitor) override {
visitor->Visit(this);
}
};
// Element 子类 Rectangle
class Rectangle : public Shape {
public:
double width, height;
Rectangle(double w, double h) : width(w), height(h) {}
void Accept(Visitor* visitor) override {
visitor->Visit(this);
}
};
// ConcreteVisitor 增加计算面积操作
class AreaVisitor : public Visitor {
public:
void Visit(Circle* circle) override {
double area = 3.14159 * circle->radius * circle->radius;
std::cout << "Circle area: " << area << std::endl;
}
void Visit(Rectangle* rectangle) override {
double area = rectangle->width * rectangle->height;
std::cout << "Rectangle area: " << area << std::endl;
}
};
int main() {
std::vector<Shape*> shapes;
shapes.push_back(new Circle(5.0));
shapes.push_back(new Rectangle(4.0, 6.0));
AreaVisitor areaVisitor;
for (auto shape : shapes) {
shape->Accept(&areaVisitor);
}
for (auto shape : shapes)
delete shape;
return 0;
}
- 分离无关的行为
【好处说明】
将不同的操作逻辑分离到独立的访问者中,使元素类只负责数据结构和接受访问者,而将具体操作逻辑移到访问者类中。比如,绘制和导出操作分别由不同访问者实现。
#include <iostream>
// 使用前面的 Shape、Circle、Rectangle 声明(略)
// ConcreteVisitor 实现绘制操作
class DrawVisitor : public Visitor {
public:
void Visit(Circle* circle) override {
std::cout << "Drawing Circle with radius " << circle->radius << std::endl;
}
void Visit(Rectangle* rectangle) override {
std::cout << "Drawing Rectangle " << rectangle->width << "x" << rectangle->height << std::endl;
}
};
int main() {
// 假设已有 shapes 数组
Circle circle(3.0);
Rectangle rectangle(2.0, 5.0);
DrawVisitor drawVisitor;
circle.Accept(&drawVisitor);
rectangle.Accept(&drawVisitor);
return 0;
}
- 集中相关行为
【好处说明】
所有与特定操作相关的逻辑被集中放在同一个访问者中,便于理解和维护。比如所有绘制操作都集中在 DrawVisitor 中。
上面第二个示例中,DrawVisitor 就集中处理了绘制逻辑,不必分散在每个图形类中,代码复用和修改都更方便。
- 增加新的访问者
【好处说明】
当需要添加新的功能时,只需创建新的访问者类,而无需更改现有的元素类。例如,增加一个导出图形数据的操作。
#include <iostream>
// 使用前面的 Shape、Circle、Rectangle 声明(略)
// ConcreteVisitor 实现导出操作
class ExportVisitor : public Visitor {
public:
void Visit(Circle* circle) override {
std::cout << "Exporting Circle data (radius=" << circle->radius << ")" << std::endl;
}
void Visit(Rectangle* rectangle) override {
std::cout << "Exporting Rectangle data (width=" << rectangle->width
<< ", height=" << rectangle->height << ")" << std::endl;
}
};
int main() {
// 假设已有 shapes 实例
Circle circle(7.0);
Rectangle rectangle(3.0, 8.0);
ExportVisitor exportVisitor;
circle.Accept(&exportVisitor);
rectangle.Accept(&exportVisitor);
return 0;
}
- 简化元素类
【好处说明】
元素类只需实现接受访问者的方法,不必包含特定操作逻辑,这使得它们的职责单一。例如,Circle 和 Rectangle 类只需提供 Accept 方法,实际操作延迟给访问者完成。
#include <iostream>
// 简化后的 Shape 类及其子类定义
class Shape {
public:
virtual void Accept(Visitor* visitor) = 0;
};
class Circle : public Shape {
public:
double radius;
Circle(double r) : radius(r) {}
void Accept(Visitor* visitor) override {
visitor->Visit(this);
}
};
class Rectangle : public Shape {
public:
double width, height;
Rectangle(double w, double h) : width(w), height(h) {}
void Accept(Visitor* visitor) override {
visitor->Visit(this);
}
};
// 这里只定义 Accept 方法,具体操作由不同的访问者完成。
// 示例调用见前面的各个示例代码
通过这几个示例可以看出,访问者模式将操作逻辑与数据结构分离,使得新增操作变得简单且不会影响原有的类结构,同时使各个具体操作高度集中、易于维护。