Java访问者模式操作元素结构

wen java案例 2

Java访问者模式操作元素结构

模式概述

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

Java访问者模式操作元素结构

核心概念

主要角色:

  • 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

优缺点分析

优点:

  1. 开闭原则:易于添加新的操作,无需修改元素类
  2. 单一职责:将相关操作集中到访问者中
  3. 数据聚合:访问者可以积累状态(如计算总和)

缺点:

  1. 违反依赖倒置:访问者依赖具体元素类
  2. 扩展困难:添加新元素类型需要修改所有访问者
  3. 破坏封装:访问者需要访问元素内部状态

适用场景

  1. 对象结构稳定,但需要经常添加新操作
  2. 需要对不同元素执行不同的操作
  3. 元素类不需要频繁变化,但操作需要经常变化

最佳实践

// 在实际开发中,可以使用更灵活的设计
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);
}

访问者模式在编译器和语法分析器等领域有广泛应用,它能够很好地处理复杂的对象结构,并将操作与数据结构分离。

抱歉,评论功能暂时关闭!