1.简介
访问者模式是一种行为型设计模式,它允许我们向现有类结构添加新的行为,而无需修改这些类。这种模式使用了一个访问者类,该类定义了一组访问方法,每个方法对应于结构中的某个类。这样,我们可以轻松地在不改变原有结构的情况下,通过创建不同的访问者来为整个结构添加新功能。
适用场景
- 当你需要对一个对象结构中的对象进行很多不同的并且不相关的操作时。
- 当对象结构中的对象有共同的操作集合时。
- 当需要对这些操作进行参数化时。
2.通俗讲解
假设我们有一个简单的图形系统,其中包含两种图形:圆形和矩形。我们希望添加一些行为,比如计算面积、绘制图形等,而不修改圆形和矩形本身的代码。
3.实战
结构体定义
- 图形接口:定义图形的基本接口,包括接受访问者的函数。
- 具体图形:实现具体的图形类。
- 访问者接口:定义访问者可以执行的行为。
- 具体访问者:实现具体的访问者类。
3.1.代码
#include <stdio.h>
// 定义图形结构体
typedef struct Graphic {
void (*accept)(struct Graphic *self, void *visitor);
} Graphic;
// 圆形结构体
typedef struct Circle {
Graphic graphic;
int radius;
} Circle;
// 矩形结构体
typedef struct Rectangle {
Graphic graphic;
int width;
int height;
} Rectangle;
// 访问者接口
typedef struct Visitor {
void (*visitCircle)(void *visitor, Circle *circle);
void (*visitRectangle)(void *visitor, Rectangle *rectangle);
} Visitor;
// 具体图形的实现
void circle_accept(Circle *self, void *visitor) {
Visitor *v = (Visitor *)visitor;
v->visitCircle(visitor, self);
}
void rectangle_accept(Rectangle *self, void *visitor) {
Visitor *v = (Visitor *)visitor;
v->visitRectangle(visitor, self);
}
// 创建圆形实例
Circle *create_circle(int radius) {
Circle *c = malloc(sizeof(Circle));
c->graphic.accept = &circle_accept;
c->radius = radius;
return c;
}
// 创建矩形实例
Rectangle *create_rectangle(int width, int height) {
Rectangle *r = malloc(sizeof(Rectangle));
r->graphic.accept = &rectangle_accept;
r->width = width;
r->height = height;
return r;
}
// 面积计算访问者
void area_visitor(void *visitor, Circle *circle) {
Visitor *v = (Visitor *)visitor;
double area = M_PI * circle->radius * circle->radius;
printf("Circle area: %.2f\n", area);
}
void area_visitor(void *visitor, Rectangle *rectangle) {
Visitor *v = (Visitor *)visitor;
int area = rectangle->width * rectangle->height;
printf("Rectangle area: %d\n", area);
}
int main() {
// 创建图形
Circle *circle = create_circle(5);
Rectangle *rectangle = create_rectangle(4, 6);
// 创建访问者
Visitor areaVisitor = {
.visitCircle = &area_visitor,
.visitRectangle = &area_visitor
};
// 使用访问者
circle->graphic.accept(circle, &areaVisitor);
rectangle->graphic.accept(rectangle, &areaVisitor);
free(circle);
free(rectangle);
return 0;
}
3.2.代码解析
- 图形结构体 (
Graphic
) 包含了一个accept
函数指针,用于调用访问者的方法。 - 具体图形 (
Circle
,Rectangle
) 继承了Graphic
并实现了自己的accept
方法。 - 访问者结构体 (
Visitor
) 包含了指向访问者方法的函数指针。 - 在
main
函数中,我们创建了一个圆形和一个矩形,然后创建了一个面积计算访问者,并使用这个访问者计算并打印出图形的面积。
3.3.代码运行
- 创建了一个半径为5的圆形。
- 创建了一个宽度为4、高度为6的矩形。
- 创建了一个面积计算访问者。
- 圆形调用了面积访问者,输出圆的面积。
- 矩形也调用了面积访问者,输出矩形的面积。
Circle area: 78.54
Rectangle area: 24