Java访问者模式实现案例
访问者模式(Visitor Pattern)是一种将数据结构与数据操作分离的设计模式,以下是一个完整的实现案例:

基础结构
// 元素接口
interface Element {
void accept(Visitor visitor);
}
// 具体元素类 - 书
class Book implements Element {
private String name;
private double price;
public Book(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() { return name; }
public double getPrice() { return price; }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 具体元素类 - 电子产品
class Electronic implements Element {
private String name;
private double price;
public Electronic(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() { return name; }
public double getPrice() { return price; }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 访问者接口
interface Visitor {
void visit(Book book);
void visit(Electronic electronic);
}
// 具体访问者 - 计算总价
class PriceCalculator implements Visitor {
private double totalPrice = 0;
@Override
public void visit(Book book) {
totalPrice += book.getPrice();
}
@Override
public void visit(Electronic electronic) {
// 电子产品加税
totalPrice += electronic.getPrice() * 1.1;
}
public double getTotalPrice() {
return totalPrice;
}
}
// 具体访问者 - 打折处理
class DiscountVisitor implements Visitor {
@Override
public void visit(Book book) {
System.out.println("书籍【" + book.getName() + "】打8折,原价:"
+ book.getPrice() + ",现价:" + book.getPrice() * 0.8);
}
@Override
public void visit(Electronic electronic) {
System.out.println("电子产品【" + electronic.getName() + "】打9折,原价:"
+ electronic.getPrice() + ",现价:" + electronic.getPrice() * 0.9);
}
}
对象结构类
import java.util.ArrayList;
import java.util.List;
class ShoppingCart {
private List<Element> items = new ArrayList<>();
public void addItem(Element item) {
items.add(item);
}
public void removeItem(Element item) {
items.remove(item);
}
public void accept(Visitor visitor) {
for (Element item : items) {
item.accept(visitor);
}
}
}
客户使用示例
public class VisitorPatternDemo {
public static void main(String[] args) {
// 创建购物车
ShoppingCart cart = new ShoppingCart();
// 添加商品
cart.addItem(new Book("设计模式", 68.0));
cart.addItem(new Book("Java编程思想", 99.0));
cart.addItem(new Electronic("笔记本电脑", 5000.0));
cart.addItem(new Electronic("手机", 3000.0));
// 使用价格计算器访问者
System.out.println("=== 计算总价 ===");
PriceCalculator priceCalculator = new PriceCalculator();
cart.accept(priceCalculator);
System.out.println("总价: " + priceCalculator.getTotalPrice());
// 使用打折访问者
System.out.println("\n=== 打折处理 ===");
DiscountVisitor discountVisitor = new DiscountVisitor();
cart.accept(discountVisitor);
}
}
运行结果
=== 计算总价 ===
总价: 8967.0
=== 打折处理 ===
书籍【设计模式】打8折,原价:68.0,现价:54.4
书籍【Java编程思想】打9折,原价:99.0,现价:79.2
电子产品【笔记本电脑】打9折,原价:5000.0,现价:4500.0
电子产品【手机】打9折,原价:3000.0,现价:2700.0
使用场景与优缺点
适用场景:
- 对象结构比较稳定,但需要经常增加新的操作
- 需要对一个对象结构中的对象进行很多不同的且不相关的操作
- 需要避免在元素类中暴露内部状态
优点:
- 符合单一职责原则,相关操作集中在访问者中
- 扩展性好,添加新操作只需添加新访问者
- 可以在不修改元素类的情况下添加新操作
缺点:
- 增加新元素困难,需要修改访问者接口
- 破坏了封装,访问者需要知道元素内部细节
- 当元素类变化频繁时不适合使用
这个案例展示了访问者模式如何优雅地分离数据结构和操作,使得添加新的操作变得简单方便。