23.设计模式-VISITOR(访问者)
一、模式定义与核心思想
访问者模式是一种行为型设计模式,其核心目标是将算法与对象结构解耦,允许在不修改现有对象结构的前提下定义新的操作。该模式通过双重分派(Double Dispatch)机制实现,使得操作可以独立于元素类进行扩展
核心价值:
- 算法与结构解耦:将业务逻辑从数据结构中剥离(如薪资计算与员工类解耦)
- 扩展性增强:新增操作只需添加新的访问者类(如新增XML导出功能无需修改员工类)
- 开闭原则遵循:对扩展开放,对修改关闭(如Spring框架中动态添加验证逻辑)
典型应用场景:
- 复杂对象结构的遍历与操作(如编译器语法树分析)
- 跨平台数据导出(如XML/JSON格式转换)
- 动态策略应用(如游戏角色状态的多维度计算)
二、模式组成与UML类图
核心角色
- Visitor(访问者接口):
-
- 声明
visit()方法,为每个具体元素类定义操作接口(如visit(Manager)和visit(Developer))。
- 声明
- ConcreteVisitor(具体访问者):
-
- 实现接口方法,包含具体业务逻辑(如薪资调整、文件导出)
- Element(元素接口):
-
- 定义
accept(Visitor)方法,将自身传递给访问者(如员工类接受薪资计算器访问)
- 定义
- ConcreteElement(具体元素):
-
- 实现
accept()方法,调用访问者的对应方法(如Manager.accept()触发visit(Manager))
- 实现
- ObjectStructure(对象结构):
-
- 维护元素集合,提供遍历接口(如公司类管理员工列表)。
UML类图
classDiagram
class Visitor {
<<interface>>
+visitConcreteElementA(ConcreteElementA)
+visitConcreteElementB(ConcreteElementB)
}
class ConcreteVisitorA {
+visitConcreteElementA(ConcreteElementA)
+visitConcreteElementB(ConcreteElementB)
}
class Element {
<<interface>>
+accept(Visitor)
}
class ConcreteElementA {
+accept(Visitor)
+operationA()
}
class ConcreteElementB {
+accept(Visitor)
+operationB()
}
class ObjectStructure {
-elements: List<Element>
+addElement(Element)
+accept(Visitor)
}
Visitor <|-- ConcreteVisitorA
Element <|-- ConcreteElementA
Element <|-- ConcreteElementB
ObjectStructure --> Element : 聚合
ConcreteElementA --> Visitor : 调用visit()
ConcreteElementB --> Visitor : 调用visit()

三、代码实现示例
场景:实现电商订单的跨格式导出(JSON/XML)
// 1. 元素接口与具体元素
interface OrderElement {
void accept(OrderVisitor visitor);
}
class Product implements OrderElement {
private String name;
private double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public void accept(OrderVisitor visitor) {
visitor.visit(this);
}
// Getters
public String getName() { return name; }
public double getPrice() { return price; }
}
// 2. 访问者接口与具体访问者
interface OrderVisitor {
void visit(Product product);
}
class JsonExportVisitor implements OrderVisitor {
@Override
public void visit(Product product) {
System.out.printf("{\"name\":\"%s\",\"price\":%.2f}\n",
product.getName(), product.getPrice());
}
}
class XmlExportVisitor implements OrderVisitor {
@Override
public void visit(Product product) {
System.out.printf("<product><name>%s</name><price>%.2f</price></product>\n",
product.getName(), product.getPrice());
}
}
// 3. 对象结构
class Order {
private List<OrderElement> items = new ArrayList<>();
public void addItem(OrderElement item) {
items.add(item);
}
public void export(OrderVisitor visitor) {
items.forEach(item -> item.accept(visitor));
}
}
// 4. 客户端调用
public class Client {
public static void main(String[] args) {
Order order = new Order();
order.addItem(new Product("Laptop", 999.99));
order.addItem(new Product("Mouse", 29.99));
System.out.println("--- JSON Export ---");
order.export(new JsonExportVisitor());
System.out.println("\n--- XML Export ---");
order.export(new XmlExportVisitor());
}
}
四、工业级源码应用
- Java编译器API:
-
javax.lang.model.element.ElementVisitor处理抽象语法树节点,支持注解处理器开发。
- Spring框架:
-
BeanDefinitionVisitor遍历Bean定义实现属性加密(如数据库密码脱敏)。
- Hibernate ORM:
-
- 通过
Visitor模式实现延迟加载策略,动态生成代理类。
- 通过
- Kubernetes客户端:
-
kubectl命令使用Visitor模式遍历API资源(如kubectl get pods的资源解析)。
- Apache Calcite:
-
- SQL查询优化器通过
RelNodeVisitor重写关系代数表达式。
- SQL查询优化器通过
五、模式优劣与最佳实践
优势:
- 新增操作成本降低70%:扩展只需新增Visitor类(如新增CSV导出器)。
- 复合操作集中管理:复杂统计(如订单总价+税费计算)可封装在单一访问者中。
局限性:
- 元素类需稳定:频繁修改元素接口会导致所有访问者类需要同步调整
- 破坏封装性:访问者可能直接操作元素内部状态(需通过接口严格控制访问权限)。
最佳实践:
- 与组合模式结合:处理树形结构时,通过Composite实现递归遍历
- 异步访问优化:高并发场景下使用
Visitor + CompletableFuture实现并行处理 - 访问者工厂:通过工厂模式动态创建访问者(如根据配置选择导出格式)
总结
访问者模式如同软件架构的"算法路由器",通过双重分派机制和逻辑集中化设计,在编译器、ORM框架等场景中展现出强大的生命力。其核心价值在于将易变的操作逻辑与稳定的数据结构分离,开发者需重点把控元素接口的稳定性,结合具体场景选择访问粒度,从而构建出高扩展、易维护的系统架构。

浙公网安备 33010602011771号