Java设计模式——访问者模式
⚪访问者模式(Visitor)是一种行为型设计模式,这个模式的核心思想是将操作从对象结构中提取出来,这样可以更容易地添加新的操作而无需修改已有的代码。
⚪意图:它允许你在不修改现有对象结构的情况下,定义新的操作并将其应用于对象结构中的元素。
⚪以下是工厂方法模式的关键要点:
▷ 角色和责任:
- 访问者(Visitor): 定义了对对象结构中的各元素进行操作的接口。这个接口通常包含多个 visit() 方法,每个方法对应一个不同类型的元素。
- 具体访问者(Concrete Visitor): 实现了访问者接口的具体类,负责实现具体的操作。
- 元素(Element): 定义了接受访问者访问的接口。通常包含一个 accept() 方法,该方法接受一个访问者作为参数。
- 具体元素(Concrete Element): 实现了元素接口的具体类,包含了接受访问者访问的具体实现。
- 对象结构(Object Structure): 包含了元素的集合,可以是一个列表、树形结构等。对象结构提供了接受访问者访问的方法,通常是遍历结构中的元素并调用它们的 accept() 方法。
▷ 工作流程:
- 具体访问者(Concrete Visitor)实现了对不同类型元素的访问操作。
- 具体元素(Concrete Element)实现了接受访问者访问的方法,并在其中调用访问者的相应方法。
- 对象结构(Object Structure)包含了元素的集合,并提供了接受访问者访问的方法。
- 客户端代码创建访问者对象和元素对象,然后通过对象结构接受访问者的访问。
▷ 示例
import java.util.*;
// 1. 元素接口
interface Shape {
void accept(Visitor visitor);
}
// 2. 具体元素
class Circle implements Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class Rectangle implements Shape {
private double width;
private double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
public double getWidth() {
return width;
}
public double getHeight() {
return height;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 3. 访问者接口
interface Visitor {
void visit(Circle circle);
void visit(Rectangle rectangle);
}
// 4. 具体访问者
class AreaCalculator implements Visitor {
private double totalArea = 0;
@Override
public void visit(Circle circle) {
// 计算圆形面积
totalArea += Math.PI * circle.getRadius() * circle.getRadius();
}
@Override
public void visit(Rectangle rectangle) {
// 计算矩形面积
totalArea += rectangle.getWidth() * rectangle.getHeight();
}
public double getTotalArea() {
return totalArea;
}
}
// 5. 对象结构
class Drawing {
private List<Shape> shapes = new ArrayList<>();
public void addShape(Shape shape) {
shapes.add(shape);
}
public void accept(Visitor visitor) {
for (Shape shape : shapes) {
shape.accept(visitor);
}
}
}
public class VisitorDemo {
public static void main(String[] args) {
Drawing drawing = new Drawing();
drawing.addShape(new Circle(5));
drawing.addShape(new Rectangle(4, 6));
AreaCalculator areaCalculator = new AreaCalculator();
drawing.accept(areaCalculator);
System.out.println("Total Area: " + areaCalculator.getTotalArea());
}
}
⚪适用性
- 一个对象结构包含很多类对象,它们有不同的接口,而用户想对这些对象实施一些依赖于其具体类的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而又想要避免这些操作“污染”这些对象的类。Visitor 使得用户可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用共享时,用 Vsitor 模式让每个应用仅包含需要用到的操作。
- 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
⚪应用场景
- 对象结构包含多个不同类型的对象,而你需要对这些对象执行一系列不同的操作,但不希望在每个对象类中添加这些操作。 访问者模式允许你将这些操作封装在独立的访问者类中,以便将来轻松地添加新操作而无需修改现有类。
- 需要在不同的对象类型上执行相似但不完全相同的操作。 访问者模式允许你为每种操作创建一个独立的访问者类,以便在不同的对象上执行这些操作。
⚪实际已有场景
- Spring AOP(面向切面编程): Spring AOP 使用了一种类似于访问者模式的机制来允许你定义横切关注点(cross-cutting concerns)的处理,例如事务管理、日志记录等。切面(Aspect)充当访问者,而被通知(Advisee)的对象充当元素。这使得你可以在不修改原始类的情况下,将横切关注点应用于不同的对象。
- Spring Data JPA: Spring Data JPA 使用了类似于访问者模式的机制来实现不同数据存储源(如关系型数据库、NoSQL 数据库等)的访问。它通过为不同的数据存储源定义不同的访问者来实现数据的持久化和查询操作。
- Spring Expression Language(SpEL): SpEL 允许你在运行时评估表达式,类似于访问者模式中的访问操作。你可以定义 SpEL 表达式并将其应用于对象来获取或修改对象的属性。

浙公网安备 33010602011771号