访问者模式(Visitor Pattern)一句话记忆:
> **“把** **对数据结构的操作** **从** **数据结构本身** **中分离出来,让同一批元素可以接受不同的‘访问者’来执行不同的行为。”**
---
### 🧩 场景类比
想象一个 **动物园**:
- **元素**:狮子、老虎、大象 …(它们是数据结构里的节点)
- **访问者**:
- **饲养员**(喂食)
- **兽医**(体检)
- **游客**(拍照)
> 动物(元素)不需要知道“谁来干什么”,
> 每个访问者只需实现“对狮子怎么做、对老虎怎么做”。
---
### 🔍 回到 Java / Lucene
#### 1. 典型 API:`Files.walkFileTree`
```java
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
// 对“文件”这个元素的操作
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
// 对“目录”这个元素的操作
return FileVisitResult.CONTINUE;
}
});
```
- **元素**:`Path` 代表的文件或目录
- **访问者**:`SimpleFileVisitor` 的匿名子类
- **好处**:新增“压缩访问者”、“统计访问者”时,**无需修改目录/文件类**。
#### 2. 结构图
```
+-------------------+ +------------------+
| 元素(File) | | 元素(Dir) |
+-------------------+ +------------------+
| accept(Visitor) | | accept(Visitor) |
+---------+---------+ +---------+--------+
| |
| +-------------------v----------------+
| | 访问者接口 |
| | + visit(File) + visit(Dir) |
| +-------------------+----------------+
| |
| +-------------------v----------------+
| | 具体访问者A:打印路径 |
| | 具体访问者B:统计大小 |
+--------> 具体访问者C:高亮内容 |
```
---
### ✅ 优缺点速记
| 优点 | 缺点 |
|---|---|
| 新增操作只需再写一个访问者,**不改动元素类** | 元素一旦新增类型,**所有访问者都要加新方法** |
---
### 🧩 一句话背下来
**“元素只负责‘接待’,访问者决定‘做什么’。”**
没有 Visitor 行不行?—— 用“动物园”故事讲透
## 没有 Visitor 行不行?—— 用“动物园”故事讲透
---
### 🐘 **情景 1:没有访问者模式**
你开了一家动物园,动物们自己“包办一切”:
```java
class Elephant {
void feed() { System.out.println("大象吃草"); }
void heal() { System.out.println("大象体检"); }
void photo() { System.out.println("大象拍照"); }
}
class Lion {
void feed() { System.out.println("狮子吃肉"); }
void heal() { System.out.println("狮子体检"); }
void photo() { System.out.println("狮子拍照"); }
}
```
#### 🚩 问题
- **每新增一种操作**(如“称重”),**所有动物类都要改一次** → **类爆炸**。
- **每新增一种动物**(如“长颈鹿”),**所有操作又要复制粘贴一次** → **违反开闭原则**。
---
### 🏗️ **情景 2:引入访问者模式**
把“操作”抽出来,动物只做“接待”:
```java
interface Animal {
void accept(Visitor v);
}
class Elephant implements Animal {
public void accept(Visitor v) { v.visit(this); }
}
interface Visitor {
void visit(Elephant e);
void visit(Lion l);
}
class FeedVisitor implements Visitor {
public void visit(Eleph