📜  访问者设计模式(1)

📅  最后修改于: 2023-12-03 14:57:40.612000             🧑  作者: Mango

访问者设计模式

访问者设计模式是一种行为型设计模式,它可以将算法与复杂的数据结构进行分离。在访问者模式中,我们可以定义一个新的操作(也称为访问者),并将其应用于一个对象的元素结构中,而不需要修改对象的类。

结构

访问者设计模式的四个角色:

  1. 访问者(Visitor):定义一个访问接口,为每个具体元素实现一个访问操作。
  2. 具体访问者(ConcreteVisitor):实现访问接口中的每个操作,完成对元素的具体访问。
  3. 元素(Element):定义一个接受访问者的方法(Accept),并传递访问者对象作为一个参数。
  4. 具体元素(ConcreteElement):实现接受访问者的方法,调用访问者中对应的操作。

下面是访问者设计模式的类图:

visitor-pattern

示例

假设我们有一个网站上有各种商品的页面,我们要给每个商品计算折扣价,并给出折扣后的价格。我们可以使用访问者设计模式来实现这个需求。

首先,我们定义一个访问者接口 Visitor,其中有两个方法,分别用于计算普通商品和折扣商品的价格。

public interface Visitor {
    double visitNormalProduct(NormalProduct normalProduct);
    double visitDiscountProduct(DiscountProduct discountProduct);
}

然后,我们定义两种商品,分别是普通商品和折扣商品,它们都实现了 Element 接口中的 accept 方法,用于将访问者对象传递进来并执行对应的操作。

public interface Element {
    double accept(Visitor visitor);
}

public class NormalProduct implements Element {
    private String name;
    private double price;

    public NormalProduct(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    @Override
    public double accept(Visitor visitor) {
        return visitor.visitNormalProduct(this);
    }
}

public class DiscountProduct implements Element {
    private String name;
    private double discount;
    private double originPrice;

    public DiscountProduct(String name, double discount, double originPrice) {
        this.name = name;
        this.discount = discount;
        this.originPrice = originPrice;
    }

    public String getName() {
        return name;
    }

    public double getDiscount() {
        return discount;
    }

    public double getOriginPrice() {
        return originPrice;
    }

    @Override
    public double accept(Visitor visitor) {
        return visitor.visitDiscountProduct(this);
    }
}

最后,我们定义两个具体访问者,分别是普通产品价格计算器和折扣产品价格计算器,它们实现了 Visitor 接口中的方法,并按照具体的算法来计算对应的价格。

public class NormalProductPriceCalculator implements Visitor {
    @Override
    public double visitNormalProduct(NormalProduct normalProduct) {
        return normalProduct.getPrice();
    }

    @Override
    public double visitDiscountProduct(DiscountProduct discountProduct) {
        return discountProduct.getOriginPrice() * discountProduct.getDiscount();
    }
}

public class DiscountProductPriceCalculator implements Visitor {
    @Override
    public double visitNormalProduct(NormalProduct normalProduct) {
        return normalProduct.getPrice() * 0.9;
    }

    @Override
    public double visitDiscountProduct(DiscountProduct discountProduct) {
        return discountProduct.getOriginPrice() * discountProduct.getDiscount() * 0.8;
    }
}

最终,我们可以像下面这样使用访问者设计模式:

Element[] elements = {new NormalProduct("电视机", 2999),
                      new DiscountProduct("苹果手机", 0.8, 5999),
                      new DiscountProduct("华为笔记本电脑", 0.75, 8999)};

Visitor normalCalculator = new NormalProductPriceCalculator();
Visitor discountCalculator = new DiscountProductPriceCalculator();

double totalPrice1 = 0;
for (Element element : elements) {
    totalPrice1 += element.accept(normalCalculator);
}
System.out.println("普通商品原价总价:" + totalPrice1);

double totalPrice2 = 0;
for (Element element : elements) {
    totalPrice2 += element.accept(discountCalculator);
}
System.out.println("折扣商品折扣价总价:" + totalPrice2);

输出结果为:

普通商品原价总价:11997.0
折扣商品折扣价总价:9898.400000000001

我们可以看到,访问者设计模式让计算器与商品具体的实现分离,使得程序更加可扩展和易维护。

优缺点
优点
  1. 可以将算法与复杂的数据结构分离,使得算法更加容易维护和复用。
  2. 可以增加新的操作而无需修改对象的类。
  3. 可以使得代码结构更清晰,易于扩展。
缺点
  1. 增加了一些新的接口和类,增加了代码的复杂度。
  2. 容易造成程序的分层结构不清晰,对于简单的程序或者结构简单的程序不适用。
总结

访问者设计模式是一种非常有用的设计模式,可以将算法与数据结构进行分离,使得代码更加可扩展和易于维护。它的核心要点在于访问者接口的定义和访问者的具体实现,通过这些可以将具体的算法和数据结构进行分离。在使用访问者设计模式时需要考虑合理的类设计和继承关系,以及良好的代码风格和命名规范。