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

核心概念
主要角色:
- Visitor(访问者):声明访问各种元素的操作接口
- ConcreteVisitor(具体访问者):实现访问者接口,定义具体操作
- Element(元素):声明接受访问者的接口
- ConcreteElement(具体元素):实现接受访问者的方法
- ObjectStructure(对象结构):管理元素集合,提供遍历机制
代码示例
1 元素接口和具体元素
// 元素接口
interface Element {
void accept(Visitor visitor);
}
// 具体元素:书
class Book implements Element {
private String title;
private double price;
public Book(String title, double price) {
this.title = title;
this.price = price;
}
public String getTitle() {
return title;
}
public double getPrice() {
return price;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 具体元素:电子产品
class Electronics implements Element {
private String name;
private double price;
private double weight;
public Electronics(String name, double price, double weight) {
this.name = name;
this.price = price;
this.weight = weight;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
public double getWeight() {
return weight;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
2 访问者接口和具体访问者
// 访问者接口
interface Visitor {
void visit(Book book);
void visit(Electronics electronics);
}
// 具体访问者:价格计算器
class PriceCalculator implements Visitor {
private double totalPrice = 0;
@Override
public void visit(Book book) {
totalPrice += book.getPrice();
System.out.println("添加书籍: " + book.getTitle() +
", 价格: " + book.getPrice());
}
@Override
public void visit(Electronics electronics) {
totalPrice += electronics.getPrice();
System.out.println("添加电子产品: " + electronics.getName() +
", 价格: " + electronics.getPrice());
}
public double getTotalPrice() {
return totalPrice;
}
}
// 具体访问者:折扣计算器
class DiscountCalculator implements Visitor {
private double totalDiscount = 0;
@Override
public void visit(Book book) {
// 书籍打8折
double discount = book.getPrice() * 0.2;
totalDiscount += discount;
System.out.println("书籍优惠: " + book.getTitle() +
", 优惠金额: " + discount);
}
@Override
public void visit(Electronics electronics) {
// 电子产品打9折
double discount = electronics.getPrice() * 0.1;
totalDiscount += discount;
System.out.println("电子产品优惠: " + electronics.getName() +
", 优惠金额: " + discount);
}
public double getTotalDiscount() {
return totalDiscount;
}
}
// 具体访问者:商品清单打印机
class InventoryPrinter implements Visitor {
@Override
public void visit(Book book) {
System.out.println("书籍 - 书名: " + book.getTitle() +
", 价格: " + book.getPrice());
}
@Override
public void visit(Electronics electronics) {
System.out.println("电子产品 - 名称: " + electronics.getName() +
", 价格: " + electronics.getPrice() +
", 重量: " + electronics.getWeight() + "kg");
}
}
3 对象结构
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 accept(Visitor visitor) {
for (Element item : items) {
item.accept(visitor);
}
}
}
4 客户端代码
public class VisitorPatternDemo {
public static void main(String[] args) {
// 创建购物车
ShoppingCart cart = new ShoppingCart();
// 添加商品
cart.addItem(new Book("Java编程思想", 89.0));
cart.addItem(new Book("设计模式", 68.0));
cart.addItem(new Electronics("笔记本电脑", 5999.0, 2.5));
cart.addItem(new Electronics("智能手机", 3999.0, 0.2));
System.out.println("=== 商品清单 ===");
cart.accept(new InventoryPrinter());
System.out.println("\n=== 价格计算 ===");
PriceCalculator priceCalc = new PriceCalculator();
cart.accept(priceCalc);
System.out.println("总价: " + priceCalc.getTotalPrice());
System.out.println("\n=== 折扣计算 ===");
DiscountCalculator discountCalc = new DiscountCalculator();
cart.accept(discountCalc);
System.out.println("总优惠: " + discountCalc.getTotalDiscount());
System.out.println("最终价格: " +
(priceCalc.getTotalPrice() - discountCalc.getTotalDiscount()));
}
}
运行结果
=== 商品清单 ===
书籍 - 书名: Java编程思想, 价格: 89.0
书籍 - 书名: 设计模式, 价格: 68.0
电子产品 - 名称: 笔记本电脑, 价格: 5999.0, 重量: 2.5kg
电子产品 - 名称: 智能手机, 价格: 3999.0, 重量: 0.2kg
=== 价格计算 ===
添加书籍: Java编程思想, 价格: 89.0
添加书籍: 设计模式, 价格: 68.0
添加笔记本电脑: 5999.0
添加智能手机: 3999.0
总价: 10155.0
=== 折扣计算 ===
书籍优惠: Java编程思想, 优惠金额: 17.8
书籍优惠: 设计模式, 优惠金额: 13.6
电子产品优惠: 笔记本电脑, 优惠金额: 599.9
电子产品优惠: 智能手机, 优惠金额: 399.9
总优惠: 1031.2
最终价格: 9123.8
优缺点分析
优点:
- 开闭原则:易于添加新的操作,无需修改元素类
- 单一职责:将相关操作集中到访问者中
- 数据聚合:访问者可以积累状态(如计算总和)
缺点:
- 违反依赖倒置:访问者依赖具体元素类
- 扩展困难:添加新元素类型需要修改所有访问者
- 破坏封装:访问者需要访问元素内部状态
适用场景
- 对象结构稳定,但需要经常添加新操作
- 需要对不同元素执行不同的操作
- 元素类不需要频繁变化,但操作需要经常变化
最佳实践
// 在实际开发中,可以使用更灵活的设计
interface ImprovedVisitor<T> {
T visit(Book book);
T visit(Electronics electronics);
}
// 或者使用泛型访问者
abstract class GenericVisitor<T> {
protected abstract T visitBook(Book book);
protected abstract T visitElectronics(Electronics electronics);
}
访问者模式在编译器和语法分析器等领域有广泛应用,它能够很好地处理复杂的对象结构,并将操作与数据结构分离。
版权声明: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直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播