Java访问者模式案例
访问者模式(Visitor Pattern)是一种行为设计模式,它允许在不修改现有类结构的情况下,为这些类添加新的操作。

核心角色
- 抽象访问者(Visitor):声明每个具体元素类的访问方法
- 具体访问者(ConcreteVisitor):实现每个访问方法
- 抽象元素(Element):声明接受访问者的方法
- 具体元素(ConcreteElement):实现接受方法
- 对象结构(ObjectStructure):管理元素集合
完整案例:文件系统分析器
import java.util.ArrayList;
import java.util.List;
// ============ 抽象元素 ============
interface FileElement {
void accept(Visitor visitor);
}
// ============ 具体元素 ============
// 文本文件
class TextFile implements FileElement {
private String name;
private int wordCount;
public TextFile(String name, int wordCount) {
this.name = name;
this.wordCount = wordCount;
}
public String getName() { return name; }
public int getWordCount() { return wordCount; }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 图片文件
class ImageFile implements FileElement {
private String name;
private int width;
private int height;
public ImageFile(String name, int width, int height) {
this.name = name;
this.width = width;
this.height = height;
}
public String getName() { return name; }
public int getWidth() { return width; }
public int getHeight() { return height; }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 文件夹
class Folder implements FileElement {
private String name;
private List<FileElement> elements = new ArrayList<>();
public Folder(String name) {
this.name = name;
}
public String getName() { return name; }
public void addElement(FileElement element) {
elements.add(element);
}
public List<FileElement> getElements() {
return elements;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// ============ 抽象访问者 ============
interface Visitor {
void visit(TextFile textFile);
void visit(ImageFile imageFile);
void visit(Folder folder);
}
// ============ 具体访问者1:文件信息收集器 ============
class FileInfoCollector implements Visitor {
private StringBuilder report = new StringBuilder();
@Override
public void visit(TextFile textFile) {
report.append(String.format("文本文件: %s (字数: %d)%n",
textFile.getName(), textFile.getWordCount()));
}
@Override
public void visit(ImageFile imageFile) {
report.append(String.format("图片文件: %s (尺寸: %dx%d)%n",
imageFile.getName(), imageFile.getWidth(), imageFile.getHeight()));
}
@Override
public void visit(Folder folder) {
report.append(String.format("文件夹: %s%n", folder.getName()));
for (FileElement element : folder.getElements()) {
element.accept(this);
}
}
public String getReport() {
return report.toString();
}
}
// ============ 具体访问者2:文件大小计算器 ============
class FileSizeCalculator implements Visitor {
private long totalSize = 0;
@Override
public void visit(TextFile textFile) {
// 假设每个字符占用2字节
totalSize += textFile.getWordCount() * 2;
System.out.println(textFile.getName() + " 大小: " + totalSize + " 字节");
}
@Override
public void visit(ImageFile imageFile) {
// 假设每个像素占用3字节
totalSize += imageFile.getWidth() * imageFile.getHeight() * 3;
System.out.println(imageFile.getName() + " 大小: " + totalSize + " 字节");
}
@Override
public void visit(Folder folder) {
System.out.println("进入文件夹: " + folder.getName());
for (FileElement element : folder.getElements()) {
element.accept(this);
}
}
public long getTotalSize() {
return totalSize;
}
}
// ============ 对象结构 ============
class FileSystem {
private List<FileElement> elements = new ArrayList<>();
public void addElement(FileElement element) {
elements.add(element);
}
public void accept(Visitor visitor) {
for (FileElement element : elements) {
element.accept(visitor);
}
}
}
// ============ 客户端 ============
public class VisitorPatternDemo {
public static void main(String[] args) {
// 创建文件系统结构
Folder root = new Folder("项目文档");
Folder srcFolder = new Folder("源代码");
TextFile mainJava = new TextFile("Main.java", 500);
TextFile utilsJava = new TextFile("Utils.java", 300);
srcFolder.addElement(mainJava);
srcFolder.addElement(utilsJava);
Folder docsFolder = new Folder("文档");
ImageFile diagram = new ImageFile("架构图.png", 1920, 1080);
TextFile readme = new TextFile("README.md", 100);
docsFolder.addElement(diagram);
docsFolder.addElement(readme);
root.addElement(srcFolder);
root.addElement(docsFolder);
// 使用不同的访问者
System.out.println("===== 文件信息报告 =====");
FileInfoCollector collector = new FileInfoCollector();
root.accept(collector);
System.out.println(collector.getReport());
System.out.println("\n===== 文件大小计算 =====");
FileSizeCalculator calculator = new FileSizeCalculator();
root.accept(calculator);
System.out.println("总大小: " + calculator.getTotalSize() + " 字节");
}
}
简化版案例:动物园访客
// 抽象动物
interface Animal {
void accept(ZooVisitor visitor);
}
// 具体动物
class Lion implements Animal {
private String name;
public Lion(String name) { this.name = name; }
public String getName() { return name; }
@Override
public void accept(ZooVisitor visitor) {
visitor.visit(this);
}
}
class Elephant implements Animal {
private String name;
public Elephant(String name) { this.name = name; }
public String getName() { return name; }
@Override
public void accept(ZooVisitor visitor) {
visitor.visit(this);
}
}
// 抽象访问者
interface ZooVisitor {
void visit(Lion lion);
void visit(Elephant elephant);
}
// 具体访问者:喂食员
class Feeder implements ZooVisitor {
@Override
public void visit(Lion lion) {
System.out.println("喂食员给狮子 " + lion.getName() + " 喂肉");
}
@Override
public void visit(Elephant elephant) {
System.out.println("喂食员给大象 " + elephant.getName() + " 喂水果");
}
}
// 具体访问者:清洁员
class Cleaner implements ZooVisitor {
@Override
public void visit(Lion lion) {
System.out.println("清洁员清理狮子 " + lion.getName() + " 的笼子");
}
@Override
public void visit(Elephant elephant) {
System.out.println("清洁员清理大象 " + elephant.getName() + " 的场地");
}
}
// 使用示例
public class ZooVisitorDemo {
public static void main(String[] args) {
List<Animal> animals = new ArrayList<>();
animals.add(new Lion("辛巴"));
animals.add(new Elephant("阿里"));
ZooVisitor feeder = new Feeder();
ZooVisitor cleaner = new Cleaner();
System.out.println("=== 喂食时间 ===");
for (Animal animal : animals) {
animal.accept(feeder);
}
System.out.println("\n=== 清洁时间 ===");
for (Animal animal : animals) {
animal.accept(cleaner);
}
}
}
使用Lambda表达式优化
import java.util.function.Consumer;
// 简化版访问者模式
interface Shape {
void accept(ShapeVisitor visitor);
}
class Circle implements Shape {
private double radius;
public Circle(double radius) { this.radius = radius; }
public double getRadius() { return radius; }
@Override
public void accept(ShapeVisitor visitor) {
visitor.visit(this);
}
}
class Rectangle implements Shape {
private double width, 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(ShapeVisitor visitor) {
visitor.visit(this);
}
}
// 使用函数式接口
@FunctionalInterface
interface ShapeVisitor {
void visit(Shape shape);
}
// 使用示例
public class LambdaVisitorDemo {
public static void main(String[] args) {
List<Shape> shapes = new ArrayList<>();
shapes.add(new Circle(5));
shapes.add(new Rectangle(3, 4));
// 使用Lambda创建访问者
ShapeVisitor areaCalc = shape -> {
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
System.out.println("圆面积: " + Math.PI * circle.getRadius() * circle.getRadius());
} else if (shape instanceof Rectangle) {
Rectangle rect = (Rectangle) shape;
System.out.println("矩形面积: " + rect.getWidth() * rect.getHeight());
}
};
shapes.forEach(shape -> shape.accept(areaCalc));
}
}
访问者模式的优势
- 开闭原则:可以轻松添加新操作而不修改现有类
- 单一职责:将相关操作集中在一个访问者中
- 扩展性好:新操作只需添加新的访问者类
适用场景
- 对象结构稳定但需要添加新操作
- 需要对不同类型对象执行不相关的操作
- 一个对象结构包含很多类,且这些类的接口不同
注意事项
- 增加新元素类型困难(需要修改所有访问者)
- 可能违反依赖倒置原则
- 适用于结构稳定但操作多变的场景
访问者模式将数据结构与操作分离,使得算法可以独立于数据结构变化。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播