定义:
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
本质:
将数据和作用于数据上的某种/些特定操作分离开来。
为ADT预留一个将来可扩展功能的“接入点”,外部实现的功能代码可以在不改变ADT本身的情况下通过delegation接入ADT。
举例说明:
/* Abstract element interface (visitable) */
public interface ItemElement {
public int accept(ShoppingCartVisitor visitor);
}
/* Concrete element */
public class Book implements ItemElement{
private double price;
...
int accept(ShoppingCartVisitor visitor) {
visitor.visit(this);
}
}
public class Fruit implements ItemElement{
private double weight;
...
int accept(ShoppingCartVisitor visitor) {
visitor.visit(this);
}
}
/* Abstract visitor interface */
public interface ShoppingCartVisitor {
int visit(Book book);
int visit(Fruit fruit);
}
public class ShoppingCartVisitorImpl implements ShoppingCartVisitor {
public int visit(Book book) {
int cost=0;
if(book.getPrice() > 50){
cost = book.getPrice()-5;
}else
cost = book.getPrice();
System.out.println("Book ISBN::"+book.getIsbnNumber()
+ " cost ="+cost);
return cost;
}
public int visit(Fruit fruit) {
int cost = fruit.getPricePerKg()*fruit.getWeight();
System.out.println(fruit.getName() + " cost = "+cost);
return cost;
}
}
public class ShoppingCartClient {
public static void main(String[] args) {
ItemElement[] items = new ItemElement[]{
new Book(20, "1234"),new Book(100, "5678"),
new Fruit(10, 2, "Banana"), new Fruit(5, 5, "Apple")};
int total = calculatePrice(items);
System.out.println("Total Cost = "+total);
}
private static int calculatePrice(ItemElement[] items) {
ShoppingCartVisitor visitor = new ShoppingCartVisitorImpl();
int sum=0;
for(ItemElement item : items)
sum = sum + item.accept(visitor);
return sum;
}
}
上述模式的复杂之处在于上述访问者模式为了实现所谓的“双重分派”,设计了一个回调再回调的机制。因为Java只支持基于多态的单分派模式,这里强行模拟出“双重分派”反而加大了代码的复杂性。
策略模式与观察者模式比较:
Visitor: behavioral pattern
Strategy: behavioral pattern
二者都是通过delegation建立两个对象的动态联系 – 但是Visitor强调是的外部定义某种对ADT的操作,该操作与ADT自身关系不大(只是访问ADT),故ADT内部只需要开放accept(visitor)即可,client通过它设定visitor操作并在外部调用。 – 而Strategy则强调是对ADT内部某些要实现的功能的相应算法的灵活替换。这些算法是ADT功能的重要组成部分,只不过是delegate到外部strategy类而已。
区别: visitor是站在外部client的角度,灵活增加对ADT的各种不同操作(哪怕ADT没实现该操作),strategy则是站在内部ADT的角度,灵活变化对其内部功能的不同配置。
总结:
访问者模式的核心思想是为了访问比较复杂的数据结构,不去改变数据结构,而是把对数据的操作抽象出来,在“访问”的过程中以回调形式在访问者中处理操作逻辑。如果要新增一组操作,那么只需要增加一个新的访问者。
访问者模式是为了抽象出作用于一组复杂对象的操作,并且后续可以新增操作而不必对现有的对象结构做任何改动。