🌟 核心思想
访问者模式允许你在不修改现有类结构的情况下,定义新的操作。就像旅行团参观城市,不同游客(访问者)对同一景点有不同的行为(拍照、写游记、购物等),而景点本身不需要改变。
🏛 现实世界类比:博物馆参观
-
博物馆展品(元素):油画、雕塑、古董(固定不变)
-
导游手册(访问者):普通游客、艺术家、历史学家(不同视角)
-
导游(调度员):安排访问者参观各个展品
🏗 四大核心角色
角色 | 作用 | 类比 |
---|---|---|
Visitor(访问者) | 定义对不同元素的访问逻辑 | 不同类型的游客 |
ConcreteVisitor(具体访问者) | 实现具体的访问行为 | 拍照游客/研究学者 |
Element(元素) | 定义accept() 方法接收访问者 | 博物馆展品 |
ObjectStructure(对象结构) | 维护元素集合,安排访问 | 博物馆导览系统 |
📜 代码示例(Java实现)
1. 定义元素接口和具体元素
java
复制
// 展品接口(所有可被访问的元素必须实现) interface Exhibit { void accept(Visitor visitor); } // 油画展品 class Painting implements Exhibit { public void accept(Visitor visitor) { visitor.visit(this); // 让访问者处理油画 } public String getPaintingInfo() { return "《蒙娜丽莎》, 达芬奇, 1503年"; } } // 雕塑展品 class Sculpture implements Exhibit { public void accept(Visitor visitor) { visitor.visit(this); // 让访问者处理雕塑 } public String getSculptureMaterial() { return "大理石雕塑"; } }
2. 定义访问者接口和具体访问者
java
复制
// 访问者接口(定义所有可能的访问操作) interface Visitor { void visit(Painting painting); void visit(Sculpture sculpture); } // 普通游客(具体访问者A) class Tourist implements Visitor { public void visit(Painting painting) { System.out.println("游客拍照: " + painting.getPaintingInfo()); } public void visit(Sculpture sculpture) { System.out.println("游客触摸: " + sculpture.getSculptureMaterial()); } } // 艺术研究员(具体访问者B) class ArtResearcher implements Visitor { public void visit(Painting painting) { System.out.println("研究员记录: " + painting.getPaintingInfo()); } public void visit(Sculpture sculpture) { System.out.println("研究员测量: " + sculpture.getSculptureMaterial()); } }
3. 对象结构(博物馆)
java
复制
import java.util.ArrayList; import java.util.List; class Museum { private List<Exhibit> exhibits = new ArrayList<>(); public void addExhibit(Exhibit exhibit) { exhibits.add(exhibit); } // 接待访问者参观所有展品 public void accept(Visitor visitor) { for (Exhibit exhibit : exhibits) { exhibit.accept(visitor); } } }
4. 客户端使用
java
复制
public class Client { public static void main(String[] args) { // 创建博物馆并添加展品 Museum museum = new Museum(); museum.addExhibit(new Painting()); museum.addExhibit(new Sculpture()); // 不同访问者参观 Visitor tourist = new Tourist(); museum.accept(tourist); /* 输出: 游客拍照: 《蒙娜丽莎》, 达芬奇, 1503年 游客触摸: 大理石雕塑 */ Visitor researcher = new ArtResearcher(); museum.accept(researcher); /* 输出: 研究员记录: 《蒙娜丽莎》, 达芬奇, 1503年 研究员测量: 大理石雕塑 */ } }
✅ 优点
✔ 开闭原则:新增访问者无需修改现有元素类
✔ 单一职责:将相关操作集中在一个访问者中
✔ 灵活性:可以在运行时选择不同访问者
❌ 缺点
✖ 元素接口变更困难:新增元素类型需要修改所有访问者
✖ 破坏封装:访问者可能需要访问元素的私有成员
🎯 适用场景
-
对象结构稳定但需要频繁新增操作
-
需要对同一组对象进行多种不相关的操作
-
需要分离对象结构和操作逻辑
典型应用:
-
编译器(AST遍历)
-
文档处理(格式转换/统计)
-
UI事件处理
🔄 对比其他模式
模式 | 目的 | 关键区别 |
---|---|---|
访问者模式 | 解耦数据结构与操作 | 双分派机制 |
策略模式 | 封装算法 | 单对象行为变化 |
迭代器模式 | 遍历集合 | 不修改元素行为 |
总结
访问者模式就像万能导游,让不同"游客"用各自的方式"参观"固定结构的对象集合。当你的系统需要在稳定结构上支持多变操作时,这个模式就是你的最佳选择!🚀
💡 设计箴言:访问者模式是"操作复杂,结构简单"场景的优雅解决方案,但过度使用可能导致系统过度复杂化。