Skip to content

访问者模式

亦称: Visitor

1. 简介

访问者模式是一种行为设计模式, 它能将算法与其所作用的对象隔离开来。它允许你在不改变对象结构的前提下(或者你不希望改变对象的结构),定义作用于这些对象元素的新操作。可以理解访问者模式把数据结构和作用于结构上的操作分离开,进行解耦。
访问者模式主要包含以下几个角色:

  • Element(元素):定义一个接受访问者的方法accept,其参数为访问者对象。
  • ConcreteElement(具体元素):实现accept方法,调用访问者的对应访问方法。
  • Visitor(访问者):定义对每一个元素(Element)访问的行为,每个行为对应一个具体元素的访问操作。
  • ConcreteVisitor(具体访问者):实现访问者定义的操作,每个操作针对不同类型的元素有不同的处理逻辑。
  • ObjectStructure(对象结构):可以遍历结构中的所有元素,提供让访问者访问元素的接口。

2. 模拟场景

在电商系统中,不想频繁修改商品对象里面的属性结构,想将具体属性计算操作分离开。

java
public interface Visitor {
    void visit(Product product);
}
java
// ConcreteVisitor 实现类
public class DiscountVisitor implements Visitor {
    private double discount;
    public DiscountVisitor(double discount) {
        this.discount = discount;
    }
    @Override
    public void visit(Product product) {
        BigDecimal price = product.getPrice();
        // 计算折扣后价格
        BigDecimal discountedPrice = price.multiply(BigDecimal.valueOf(discount));
        System.out.println(product.getName() + " 的折扣价格为:" + discountedPrice);
    }
}
java
// ConcreteVisitor 实现类
public class PointVisitor implements Visitor {

    private double pointRate;
    public PointVisitor(double pointRate) {
        this.pointRate = pointRate;
    }
    @Override
    public void visit(Product product) {
        BigDecimal price = product.getPrice();
        // 计算积分
        BigDecimal point = price.multiply(BigDecimal.valueOf(pointRate));
        System.out.println(product.getName() + " 的折扣积分为:" + point);
    }
}
java
// ConcreteElement 实现类
// 具体元素类,实现了 accept 方法,用于接受访问者的访问
public class Product {

    private String name;

    private Double weight;

    private BigDecimal price;

    public Product(String name, Double weight, BigDecimal price) {
        this.name = name;
        this.weight = weight;
        this.price = price;
    }

   ....// get set方法

    public void accept(Visitor visitor) {
        // 把自己传给访问者
        visitor.visit(this);
    }
}
java
public class VisitorPatternDemo {

    public static void main(String[] args) {
        Product laptop = new Product("电脑", 1000.0, new BigDecimal("10000.00"));
        DiscountVisitor discountVisitor = new DiscountVisitor(0.8);
        PointVisitor pointVisitor = new PointVisitor(0.1);
        // 计算折扣和积分
        laptop.accept(discountVisitor);
        laptop.accept(pointVisitor);
    }
}

运行结果:
Alt text

3. 解决方案

4. Java中的类

  • javax.lang.model.element.AnnotationValue和Annotation­Value­Visitor
  • javax.lang.model.element.Element和Element­Visitor
  • javax.lang.model.type.TypeMirror和Type­Visitor
  • java.nio.file.FileVisitor和Simple­File­Visitor
  • javax.faces.component.visit.VisitContext和Visit­Callback