访问者模式
大约 14 分钟
访问者模式
什么是访问者模式
访问者模式(Visitor Pattern)是一种行为型设计模式,它表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式将数据结构与数据操作分离,使得可以在不修改现有类的情况下增加新的操作。
访问者模式的核心思想是:
- 将数据结构与数据操作分离
- 在不修改元素类的前提下定义新的操作
- 通过双重分发机制实现操作的动态绑定
- 将相关操作集中到访问者类中
为什么需要访问者模式
在实际开发中,我们经常会遇到需要对一个复杂的对象结构进行多种不同操作的情况。如果将这些操作都放在元素类中,会导致元素类变得臃肿,违反单一职责原则。而且当需要增加新的操作时,必须修改所有元素类,违反开闭原则。访问者模式通过将操作封装到独立的访问者类中,使得增加新的操作变得更加容易,同时也保持了元素类的简洁性。
访问者模式的结构
访问者模式包含以下几个角色:
- 抽象访问者(Visitor):定义一个访问具体元素的接口,为每种具体元素类声明一个访问方法
- 具体访问者(ConcreteVisitor):实现抽象访问者声明的各个访问方法,定义对每种元素的访问操作
- 抽象元素(Element):定义一个accept方法,以一个访问者为参数
- 具体元素(ConcreteElement):实现accept方法,在accept方法中调用访问者的访问方法
- 对象结构(ObjectStructure):能枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素
访问者模式的实现
基本实现
// 抽象访问者
interface Visitor {
void visitConcreteElementA(ConcreteElementA element);
void visitConcreteElementB(ConcreteElementB element);
}
// 抽象元素
abstract class Element {
public abstract void accept(Visitor visitor);
}
// 具体元素A
class ConcreteElementA extends Element {
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementA(this);
}
public void operationA() {
System.out.println("具体元素A的操作");
}
}
// 具体元素B
class ConcreteElementB extends Element {
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementB(this);
}
public void operationB() {
System.out.println("具体元素B的操作");
}
}
// 具体访问者1
class ConcreteVisitor1 implements Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA element) {
System.out.println("访问者1访问具体元素A");
element.operationA();
}
@Override
public void visitConcreteElementB(ConcreteElementB element) {
System.out.println("访问者1访问具体元素B");
element.operationB();
}
}
// 具体访问者2
class ConcreteVisitor2 implements Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA element) {
System.out.println("访问者2访问具体元素A");
element.operationA();
}
@Override
public void visitConcreteElementB(ConcreteElementB element) {
System.out.println("访问者2访问具体元素B");
element.operationB();
}
}
// 对象结构
class ObjectStructure {
private List<Element> elements = new ArrayList<>();
public void attach(Element element) {
elements.add(element);
}
public void detach(Element element) {
elements.remove(element);
}
public void accept(Visitor visitor) {
for (Element element : elements) {
element.accept(visitor);
}
}
}
// 使用示例
public class VisitorDemo {
public static void main(String[] args) {
// 创建对象结构
ObjectStructure structure = new ObjectStructure();
// 添加元素
structure.attach(new ConcreteElementA());
structure.attach(new ConcreteElementB());
structure.attach(new ConcreteElementA());
// 接受不同的访问者
System.out.println("=== 访问者模式演示 ===");
System.out.println("1. 接受访问者1:");
structure.accept(new ConcreteVisitor1());
System.out.println("\n2. 接受访问者2:");
structure.accept(new ConcreteVisitor2());
}
}
改进的实现(带返回值)
// 改进的抽象访问者(带返回值)
interface ImprovedVisitor {
String visitConcreteElementA(ConcreteElementA element);
String visitConcreteElementB(ConcreteElementB element);
}
// 改进的抽象元素
abstract class ImprovedElement {
public abstract String accept(ImprovedVisitor visitor);
}
// 改进的具体元素A
class ImprovedConcreteElementA extends ImprovedElement {
private String name;
public ImprovedConcreteElementA(String name) {
this.name = name;
}
@Override
public String accept(ImprovedVisitor visitor) {
return visitor.visitConcreteElementA(this);
}
public String getName() {
return name;
}
public void operationA() {
System.out.println("具体元素A(" + name + ")的操作");
}
}
// 改进的具体元素B
class ImprovedConcreteElementB extends ImprovedElement {
private int value;
public ImprovedConcreteElementB(int value) {
this.value = value;
}
@Override
public String accept(ImprovedVisitor visitor) {
return visitor.visitConcreteElementB(this);
}
public int getValue() {
return value;
}
public void operationB() {
System.out.println("具体元素B(值: " + value + ")的操作");
}
}
// 改进的具体访问者1
class ImprovedConcreteVisitor1 implements ImprovedVisitor {
@Override
public String visitConcreteElementA(ImprovedConcreteElementA element) {
element.operationA();
return "访问者1处理了元素A: " + element.getName();
}
@Override
public String visitConcreteElementB(ImprovedConcreteElementB element) {
element.operationB();
return "访问者1处理了元素B: " + element.getValue();
}
}
// 改进的具体访问者2
class ImprovedConcreteVisitor2 implements ImprovedVisitor {
@Override
public String visitConcreteElementA(ImprovedConcreteElementA element) {
element.operationA();
return "访问者2处理了元素A: " + element.getName().toUpperCase();
}
@Override
public String visitConcreteElementB(ImprovedConcreteElementB element) {
element.operationB();
return "访问者2处理了元素B: " + (element.getValue() * 2);
}
}
// 改进的对象结构
class ImprovedObjectStructure {
private List<ImprovedElement> elements = new ArrayList<>();
public void attach(ImprovedElement element) {
elements.add(element);
}
public void detach(ImprovedElement element) {
elements.remove(element);
}
public List<String> accept(ImprovedVisitor visitor) {
List<String> results = new ArrayList<>();
for (ImprovedElement element : elements) {
results.add(element.accept(visitor));
}
return results;
}
}
// 使用示例
public class ImprovedVisitorDemo {
public static void main(String[] args) {
// 创建对象结构
ImprovedObjectStructure structure = new ImprovedObjectStructure();
// 添加元素
structure.attach(new ImprovedConcreteElementA("元素A1"));
structure.attach(new ImprovedConcreteElementB(100));
structure.attach(new ImprovedConcreteElementA("元素A2"));
structure.attach(new ImprovedConcreteElementB(200));
// 接受不同的访问者
System.out.println("=== 改进的访问者模式演示 ===");
System.out.println("1. 接受访问者1:");
List<String> results1 = structure.accept(new ImprovedConcreteVisitor1());
for (String result : results1) {
System.out.println(" " + result);
}
System.out.println("\n2. 接受访问者2:");
List<String> results2 = structure.accept(new ImprovedConcreteVisitor2());
for (String result : results2) {
System.out.println(" " + result);
}
}
}
访问者模式的应用场景
- 编译器设计:对抽象语法树进行类型检查、代码生成等操作
- XML文档处理:对XML节点进行不同的处理操作
- 图形界面:对UI组件进行渲染、事件处理等操作
- 财务系统:对不同类型的财务数据进行统计、报表生成等操作
- 购物车系统:对不同商品进行价格计算、折扣计算等操作
- 文件系统:对不同类型的文件进行压缩、加密等操作
访问者模式的优缺点
优点
- 扩展性好:增加新的操作无须修改元素类
- 符合单一职责原则:相关操作集中在访问者类中
- 灵活性高:可以在运行时选择不同的访问者
- 数据操作与数据结构分离:保持元素类的简洁性
缺点
- 违反开闭原则:增加新的元素类需要修改访问者接口
- 具体元素对访问者公布细节:破坏了元素的封装性
- 违反依赖倒置原则:具体元素依赖于具体访问者
- 难以处理元素类层次结构:对于复杂的继承体系处理困难
访问者模式与其他模式的比较
与迭代器模式的区别
- 访问者模式:关注对元素执行操作
- 迭代器模式:关注遍历元素
与命令模式的区别
- 访问者模式:对对象结构中的元素执行操作
- 命令模式:封装请求作为对象
与策略模式的区别
- 访问者模式:为元素定义新的操作
- 策略模式:封装算法族供客户端选择
实际项目中的应用
// 购物车系统示例
// 商品抽象类
abstract class Product {
protected String name;
protected double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
public abstract void accept(ShoppingCartVisitor visitor);
}
// 书籍商品
class Book extends Product {
private String author;
private int pages;
public Book(String name, double price, String author, int pages) {
super(name, price);
this.author = author;
this.pages = pages;
}
public String getAuthor() {
return author;
}
public int getPages() {
return pages;
}
@Override
public void accept(ShoppingCartVisitor visitor) {
visitor.visit(this);
}
}
// 水果商品
class Fruit extends Product {
private double weight;
private String origin;
public Fruit(String name, double pricePerKg, double weight, String origin) {
super(name, pricePerKg * weight);
this.weight = weight;
this.origin = origin;
}
public double getWeight() {
return weight;
}
public String getOrigin() {
return origin;
}
@Override
public void accept(ShoppingCartVisitor visitor) {
visitor.visit(this);
}
}
// 电子产品商品
class Electronics extends Product {
private String brand;
private int warranty;
public Electronics(String name, double price, String brand, int warranty) {
super(name, price);
this.brand = brand;
this.warranty = warranty;
}
public String getBrand() {
return brand;
}
public int getWarranty() {
return warranty;
}
@Override
public void accept(ShoppingCartVisitor visitor) {
visitor.visit(this);
}
}
// 购物车访问者接口
interface ShoppingCartVisitor {
double visit(Book book);
double visit(Fruit fruit);
double visit(Electronics electronics);
}
// 价格计算访问者
class PriceCalculatorVisitor implements ShoppingCartVisitor {
@Override
public double visit(Book book) {
double price = book.getPrice();
System.out.println("书籍: " + book.getName() + " - 价格: $" + String.format("%.2f", price));
return price;
}
@Override
public double visit(Fruit fruit) {
double price = fruit.getPrice();
System.out.println("水果: " + fruit.getName() + " - 重量: " + fruit.getWeight() + "kg - 价格: $" + String.format("%.2f", price));
return price;
}
@Override
public double visit(Electronics electronics) {
double price = electronics.getPrice();
System.out.println("电子产品: " + electronics.getName() + " - 品牌: " + electronics.getBrand() + " - 价格: $" + String.format("%.2f", price));
return price;
}
}
// 折扣计算访问者
class DiscountCalculatorVisitor implements ShoppingCartVisitor {
@Override
public double visit(Book book) {
double originalPrice = book.getPrice();
double discount = 0.1; // 书籍10%折扣
double discountedPrice = originalPrice * (1 - discount);
System.out.println("书籍: " + book.getName() + " - 原价: $" + String.format("%.2f", originalPrice) +
" - 折扣: " + (discount * 100) + "% - 折后价: $" + String.format("%.2f", discountedPrice));
return discountedPrice;
}
@Override
public double visit(Fruit fruit) {
double originalPrice = fruit.getPrice();
double discount = 0.05; // 水果5%折扣
double discountedPrice = originalPrice * (1 - discount);
System.out.println("水果: " + fruit.getName() + " - 原价: $" + String.format("%.2f", originalPrice) +
" - 折扣: " + (discount * 100) + "% - 折后价: $" + String.format("%.2f", discountedPrice));
return discountedPrice;
}
@Override
public double visit(Electronics electronics) {
double originalPrice = electronics.getPrice();
double discount = 0.15; // 电子产品15%折扣
double discountedPrice = originalPrice * (1 - discount);
System.out.println("电子产品: " + electronics.getName() + " - 原价: $" + String.format("%.2f", originalPrice) +
" - 折扣: " + (discount * 100) + "% - 折后价: $" + String.format("%.2f", discountedPrice));
return discountedPrice;
}
}
// 税费计算访问者
class TaxCalculatorVisitor implements ShoppingCartVisitor {
@Override
public double visit(Book book) {
double price = book.getPrice();
double tax = 0.0; // 书籍免税
double totalPrice = price + tax;
System.out.println("书籍: " + book.getName() + " - 价格: $" + String.format("%.2f", price) +
" - 税费: $" + String.format("%.2f", tax) + " - 含税价: $" + String.format("%.2f", totalPrice));
return totalPrice;
}
@Override
public double visit(Fruit fruit) {
double price = fruit.getPrice();
double taxRate = 0.05; // 水果5%税费
double tax = price * taxRate;
double totalPrice = price + tax;
System.out.println("水果: " + fruit.getName() + " - 价格: $" + String.format("%.2f", price) +
" - 税费: $" + String.format("%.2f", tax) + " - 含税价: $" + String.format("%.2f", totalPrice));
return totalPrice;
}
@Override
public double visit(Electronics electronics) {
double price = electronics.getPrice();
double taxRate = 0.13; // 电子产品13%税费
double tax = price * taxRate;
double totalPrice = price + tax;
System.out.println("电子产品: " + electronics.getName() + " - 价格: $" + String.format("%.2f", price) +
" - 税费: $" + String.format("%.2f", tax) + " - 含税价: $" + String.format("%.2f", totalPrice));
return totalPrice;
}
}
// 购物车类
class ShoppingCart {
private List<Product> products = new ArrayList<>();
public void addProduct(Product product) {
products.add(product);
}
public void removeProduct(Product product) {
products.remove(product);
}
public double calculateTotal(ShoppingCartVisitor visitor) {
double total = 0;
for (Product product : products) {
total += product.accept(visitor);
}
return total;
}
public void displayCart() {
System.out.println("购物车中的商品:");
for (Product product : products) {
System.out.println(" " + product.getName() + " - $" + String.format("%.2f", product.getPrice()));
}
}
}
// 使用示例
public class ShoppingCartDemo {
public static void main(String[] args) {
// 创建购物车
ShoppingCart cart = new ShoppingCart();
// 添加商品
cart.addProduct(new Book("Java设计模式", 59.99, "Gang of Four", 395));
cart.addProduct(new Fruit("苹果", 12.0, 2.5, "山东"));
cart.addProduct(new Electronics("智能手机", 2999.99, "Apple", 12));
cart.addProduct(new Book("算法导论", 128.0, "Thomas H. Cormen", 1312));
cart.addProduct(new Fruit("香蕉", 8.0, 1.2, "海南"));
// 显示购物车
System.out.println("=== 购物车系统演示 ===");
cart.displayCart();
// 计算原价
System.out.println("\n1. 计算原价:");
double originalTotal = cart.calculateTotal(new PriceCalculatorVisitor());
System.out.println("商品原价总计: $" + String.format("%.2f", originalTotal));
// 计算折扣价
System.out.println("\n2. 计算折扣价:");
double discountedTotal = cart.calculateTotal(new DiscountCalculatorVisitor());
System.out.println("折扣价总计: $" + String.format("%.2f", discountedTotal));
// 计算含税价
System.out.println("\n3. 计算含税价:");
double taxTotal = cart.calculateTotal(new TaxCalculatorVisitor());
System.out.println("含税价总计: $" + String.format("%.2f", taxTotal));
}
}
// 文件系统示例
// 文件系统节点抽象类
abstract class FileSystemNode {
protected String name;
public FileSystemNode(String name) {
this.name = name;
}
public String getName() {
return name;
}
public abstract void accept(FileSystemVisitor visitor);
}
// 文件类
class FileNode extends FileSystemNode {
private long size;
private String extension;
public FileNode(String name, long size, String extension) {
super(name);
this.size = size;
this.extension = extension;
}
public long getSize() {
return size;
}
public String getExtension() {
return extension;
}
@Override
public void accept(FileSystemVisitor visitor) {
visitor.visit(this);
}
}
// 目录类
class DirectoryNode extends FileSystemNode {
private List<FileSystemNode> children = new ArrayList<>();
public DirectoryNode(String name) {
super(name);
}
public void addNode(FileSystemNode node) {
children.add(node);
}
public void removeNode(FileSystemNode node) {
children.remove(node);
}
public List<FileSystemNode> getChildren() {
return new ArrayList<>(children);
}
@Override
public void accept(FileSystemVisitor visitor) {
visitor.visit(this);
}
}
// 文件系统访问者接口
interface FileSystemVisitor {
void visit(FileNode file);
void visit(DirectoryNode directory);
}
// 文件统计访问者
class FileStatisticsVisitor implements FileSystemVisitor {
private int fileCount = 0;
private int directoryCount = 0;
private long totalSize = 0;
private Map<String, Integer> extensionCount = new HashMap<>();
@Override
public void visit(FileNode file) {
fileCount++;
totalSize += file.getSize();
String extension = file.getExtension().toLowerCase();
extensionCount.put(extension, extensionCount.getOrDefault(extension, 0) + 1);
}
@Override
public void visit(DirectoryNode directory) {
directoryCount++;
// 递归访问子节点
for (FileSystemNode child : directory.getChildren()) {
child.accept(this);
}
}
public int getFileCount() {
return fileCount;
}
public int getDirectoryCount() {
return directoryCount;
}
public long getTotalSize() {
return totalSize;
}
public Map<String, Integer> getExtensionCount() {
return new HashMap<>(extensionCount);
}
public void printStatistics() {
System.out.println("文件统计信息:");
System.out.println(" 文件数量: " + fileCount);
System.out.println(" 目录数量: " + directoryCount);
System.out.println(" 总大小: " + formatSize(totalSize));
System.out.println(" 文件类型统计:");
extensionCount.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.forEach(entry ->
System.out.println(" " + entry.getKey() + ": " + entry.getValue() + " 个"));
}
private String formatSize(long size) {
if (size < 1024) return size + " B";
if (size < 1024 * 1024) return String.format("%.2f KB", size / 1024.0);
if (size < 1024 * 1024 * 1024) return String.format("%.2f MB", size / (1024.0 * 1024));
return String.format("%.2f GB", size / (1024.0 * 1024 * 1024));
}
}
// 文件搜索访问者
class FileSearchVisitor implements FileSystemVisitor {
private String searchPattern;
private List<FileSystemNode> foundNodes = new ArrayList<>();
public FileSearchVisitor(String searchPattern) {
this.searchPattern = searchPattern.toLowerCase();
}
@Override
public void visit(FileNode file) {
if (file.getName().toLowerCase().contains(searchPattern) ||
file.getExtension().toLowerCase().contains(searchPattern)) {
foundNodes.add(file);
}
}
@Override
public void visit(DirectoryNode directory) {
if (directory.getName().toLowerCase().contains(searchPattern)) {
foundNodes.add(directory);
}
// 递归搜索子节点
for (FileSystemNode child : directory.getChildren()) {
child.accept(this);
}
}
public List<FileSystemNode> getFoundNodes() {
return new ArrayList<>(foundNodes);
}
public void printResults() {
System.out.println("搜索 '" + searchPattern + "' 的结果:");
if (foundNodes.isEmpty()) {
System.out.println(" 未找到匹配的文件或目录");
} else {
for (FileSystemNode node : foundNodes) {
if (node instanceof FileNode) {
FileNode file = (FileNode) node;
System.out.println(" 文件: " + file.getName() + "." + file.getExtension() +
" (" + formatSize(file.getSize()) + ")");
} else {
DirectoryNode dir = (DirectoryNode) node;
System.out.println(" 目录: " + dir.getName() + "/");
}
}
System.out.println(" 总共找到 " + foundNodes.size() + " 个项目");
}
}
private String formatSize(long size) {
if (size < 1024) return size + " B";
if (size < 1024 * 1024) return String.format("%.2f KB", size / 1024.0);
if (size < 1024 * 1024 * 1024) return String.format("%.2f MB", size / (1024.0 * 1024));
return String.format("%.2f GB", size / (1024.0 * 1024 * 1024));
}
}
// 文件加密访问者
class FileEncryptionVisitor implements FileSystemVisitor {
private String encryptionMethod;
public FileEncryptionVisitor(String encryptionMethod) {
this.encryptionMethod = encryptionMethod;
}
@Override
public void visit(FileNode file) {
if (isEncryptable(file)) {
System.out.println("使用 " + encryptionMethod + " 加密文件: " + file.getName() + "." + file.getExtension() +
" (" + formatSize(file.getSize()) + ")");
}
}
@Override
public void visit(DirectoryNode directory) {
System.out.println("处理目录: " + directory.getName() + "/");
// 递归处理子节点
for (FileSystemNode child : directory.getChildren()) {
child.accept(this);
}
}
private boolean isEncryptable(FileNode file) {
// 只加密特定类型的文件
String extension = file.getExtension().toLowerCase();
return extension.equals("txt") || extension.equals("doc") || extension.equals("pdf");
}
private String formatSize(long size) {
if (size < 1024) return size + " B";
if (size < 1024 * 1024) return String.format("%.2f KB", size / 1024.0);
if (size < 1024 * 1024 * 1024) return String.format("%.2f MB", size / (1024.0 * 1024));
return String.format("%.2f GB", size / (1024.0 * 1024 * 1024));
}
}
// 使用示例
public class FileSystemDemo {
public static void main(String[] args) {
// 构建文件系统结构
DirectoryNode root = new DirectoryNode("根目录");
DirectoryNode documents = new DirectoryNode("文档");
documents.addNode(new FileNode("简历", 102400, "doc"));
documents.addNode(new FileNode("报告", 204800, "pdf"));
documents.addNode(new FileNode("笔记", 51200, "txt"));
DirectoryNode images = new DirectoryNode("图片");
images.addNode(new FileNode("照片1", 2048000, "jpg"));
images.addNode(new FileNode("照片2", 3072000, "png"));
images.addNode(new FileNode("图表", 1024000, "svg"));
DirectoryNode projects = new DirectoryNode("项目");
projects.addNode(new FileNode("源代码", 512000, "java"));
projects.addNode(new FileNode("配置文件", 2048, "xml"));
DirectoryNode javaProject = new DirectoryNode("Java项目");
javaProject.addNode(new FileNode("Main", 2048, "java"));
javaProject.addNode(new FileNode("README", 1024, "md"));
projects.addNode(javaProject);
root.addNode(documents);
root.addNode(images);
root.addNode(projects);
root.addNode(new FileNode("说明", 2048, "txt"));
System.out.println("=== 文件系统访问者模式演示 ===");
// 文件统计
System.out.println("1. 文件统计:");
FileStatisticsVisitor statsVisitor = new FileStatisticsVisitor();
root.accept(statsVisitor);
statsVisitor.printStatistics();
// 文件搜索
System.out.println("\n2. 搜索包含'项目'的文件和目录:");
FileSearchVisitor searchVisitor = new FileSearchVisitor("项目");
root.accept(searchVisitor);
searchVisitor.printResults();
// 文件加密
System.out.println("\n3. 加密文档文件:");
FileEncryptionVisitor encryptionVisitor = new FileEncryptionVisitor("AES-256");
documents.accept(encryptionVisitor);
}
}
Java中的访问者模式应用
// Java注解处理中的访问者模式
import javax.lang.model.element.*;
import javax.lang.model.util.*;
// 模拟ElementVisitor的简化实现
interface SimpleElementVisitor<R, P> {
R visitPackage(PackageElement e, P p);
R visitType(TypeElement e, P p);
R visitVariable(VariableElement e, P p);
R visitExecutable(ExecutableElement e, P p);
}
// 具体元素 - 模拟Element的实现
abstract class SimpleElement {
protected String name;
public SimpleElement(String name) {
this.name = name;
}
public String getName() {
return name;
}
public abstract <R, P> R accept(SimpleElementVisitor<R, P> visitor, P p);
}
// 包元素
class SimplePackageElement extends SimpleElement {
public SimplePackageElement(String name) {
super(name);
}
@Override
public <R, P> R accept(SimpleElementVisitor<R, P> visitor, P p) {
return visitor.visitPackage(this, p);
}
}
// 类型元素
class SimpleTypeElement extends SimpleElement {
public SimpleTypeElement(String name) {
super(name);
}
@Override
public <R, P> R accept(SimpleElementVisitor<R, P> visitor, P p) {
return visitor.visitType(this, p);
}
}
// 变量元素
class SimpleVariableElement extends SimpleElement {
public SimpleVariableElement(String name) {
super(name);
}
@Override
public <R, P> R accept(SimpleElementVisitor<R, P> visitor, P p) {
return visitor.visitVariable(this, p);
}
}
// 可执行元素
class SimpleExecutableElement extends SimpleElement {
public SimpleExecutableElement(String name) {
super(name);
}
@Override
public <R, P> R accept(SimpleElementVisitor<R, P> visitor, P p) {
return visitor.visitExecutable(this, p);
}
}
// 具体访问者 - 代码生成访问者
class CodeGenerationVisitor implements SimpleElementVisitor<String, String> {
@Override
public String visitPackage(SimplePackageElement e, String p) {
return "package " + e.getName() + ";\n";
}
@Override
public String visitType(SimpleTypeElement e, String p) {
return "public class " + e.getName() + " {\n}\n";
}
@Override
public String visitVariable(SimpleVariableElement e, String p) {
return " private " + p + " " + e.getName() + ";\n";
}
@Override
public String visitExecutable(SimpleExecutableElement e, String p) {
return " public " + p + " " + e.getName() + "() {\n // TODO: 实现方法\n }\n";
}
}
// 具体访问者 - 文档生成访问者
class DocumentationVisitor implements SimpleElementVisitor<String, String> {
@Override
public String visitPackage(SimplePackageElement e, String p) {
return "Package: " + e.getName() + "\n";
}
@Override
public String visitType(SimpleTypeElement e, String p) {
return "Class: " + e.getName() + "\n";
}
@Override
public String visitVariable(SimpleVariableElement e, String p) {
return "Field: " + e.getName() + " (Type: " + p + ")\n";
}
@Override
public String visitExecutable(SimpleExecutableElement e, String p) {
return "Method: " + e.getName() + " (Return Type: " + p + ")\n";
}
}
// 使用示例
public class JavaAnnotationVisitorDemo {
public static void main(String[] args) {
System.out.println("=== Java注解处理访问者模式演示 ===");
// 创建元素
SimplePackageElement packageElement = new SimplePackageElement("com.example");
SimpleTypeElement classElement = new SimpleTypeElement("MyClass");
SimpleVariableElement fieldElement = new SimpleVariableElement("myField");
SimpleExecutableElement methodElement = new SimpleExecutableElement("myMethod");
// 代码生成访问者
System.out.println("1. 代码生成:");
CodeGenerationVisitor codeVisitor = new CodeGenerationVisitor();
System.out.print(packageElement.accept(codeVisitor, null));
System.out.print(classElement.accept(codeVisitor, null));
System.out.print(fieldElement.accept(codeVisitor, "String"));
System.out.print(methodElement.accept(codeVisitor, "void"));
// 文档生成访问者
System.out.println("\n2. 文档生成:");
DocumentationVisitor docVisitor = new DocumentationVisitor();
System.out.print(packageElement.accept(docVisitor, null));
System.out.print(classElement.accept(docVisitor, null));
System.out.print(fieldElement.accept(docVisitor, "String"));
System.out.print(methodElement.accept(docVisitor, "void"));
}
}
总结
访问者模式是一种非常实用的行为型设计模式,它表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式将数据结构与数据操作分离,使得可以在不修改现有类的情况下增加新的操作。
使用访问者模式的关键点:
- 识别需要对复杂对象结构进行多种操作的场景
- 定义访问者接口和具体访问者类
- 在元素类中实现accept方法
- 通过对象结构管理元素集合
访问者模式的优点是扩展性好,符合单一职责原则,灵活性高,数据操作与数据结构分离。但需要注意的是,违反开闭原则(增加新元素需要修改访问者接口),具体元素对访问者公布细节,违反依赖倒置原则。在现代Java开发中,访问者模式广泛应用于编译器设计、XML文档处理、图形界面、财务系统等需要对复杂对象结构进行多种操作的场景。Java标准库中的注解处理API等都使用了访问者模式。