该模式的主要目的是将数据结构与数据操作分离,避免在对一个对象结构中的对象进行很多不同的并且不相关的操作时,这些操作"污染"这些对象的类。使用访问者模式将这些封装到类中。
比如现在我们很多人都喜欢网上购物,一般流程都是“浏览商品信息—>付款—>收到商品后评价”。如果将整个购物过程看成是个整体,则这个整体可以看成由上面三部分组成。对于每个不同的小部分,顾客(也就是模式中的访问者)的操作也不同。
访问者模式包含以下主要角色:
以顾客购物为例
抽象访问者接口:
public interface Visitor {
public void visit(BrowseProduct section);
public void visit(Pay section);
public void visit(Reviews section);
}
抽象元素接口,无论浏览商品还是付款或者评价都属于购物这个抽象概念:
public interface Shopping {
public void accept(Visitor visitor);
}
三个具体元素类,也就是三个不同的购物过程:
// 浏览商品
public class BrowseProduct implements Shopping {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operation() {
// 这里可以添加详细的浏览过程
return "已获取商品信息";
}
}
// 付款
public class Pay implements Shopping {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operation() {
return "付款成功";
}
}
// 商品评价
public class Reviews implements Shopping {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operation() {
return "完成评价";
}
}
具体访问者,也就是顾客:
public class Customer implements Visitor {
@Override
public void visit(BrowseProduct section) {
System.out.println("浏览商品信息——>" + section.operation());
}
@Override
public void visit(Pay section) {
System.out.println("准备付款——>" + section.operation());
}
@Override
public void visit(Reviews section) {
System.out.println("收货后评价——>" + section.operation());
}
}
对象结构类,将购物过程的所有具体部分聚合在一起:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ShoppingStructure {
private List<Shopping> list = new ArrayList<>();
public void accept(Visitor visitor) {
Iterator<Shopping> it = list.iterator();
while (it.hasNext()) {
((Shopping) it.next()).accept(visitor);
}
}
public void add(Shopping section) {
list.add(section);
}
public void remove(Shopping section) {
list.remove(section);
}
}
最后就是外部类中创建访问者模拟购物的不同操作:
public class VisitorPattern {
public static void main(String[] args) {
// 创建购物过程
ShoppingStructure structure = new ShoppingStructure();
structure.add(new BrowseProduct());
structure.add(new Pay());
structure.add(new Reviews());
System.out.println("顾客开始购物...");
Visitor customer = new Customer();
structure.accept(customer);
}
}
上面只提供了一个访问者类型,如果需要增加不同类型的访问者,比如店铺店主,那么访问者类型不同时对各部分的具体操作可能也不一样。比如付款环节顾客支付,店主查看顾客是否已付款。这时候就需要再次实现下 Visitor 接口创建个店主类,在付款部分将具体操作 operation() 方法以不同参数形式多次实现,参数为不同的访问者类型。
具体修改如下:
修改三个具体购物过程中的 operation() 方法:
public class BrowseProduct implements Shopping {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operation(Customer customer) {
return "顾客浏览商品信息";
}
public String operation(Boss boss) {
return "店主浏览商品信息";
}
}
public class Pay implements Shopping {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operation(Customer customer) {
return "顾客付款";
}
public String operation(Boss boss) {
return "店主查看顾客是否付款";
}
}
public class Customer implements Visitor {
@Override
public void visit(BrowseProduct section) {
System.out.println("浏览商品环节——>" + section.operation(this));
}
@Override
public void visit(Pay section) {
System.out.println("付款环节——>" + section.operation(this));
}
@Override
public void visit(Reviews section) {
System.out.println("评价环节——>" + section.operation(this));
}
}
原顾客类中 operation() 方法添加参数:
public class Customer implements Visitor {
@Override
public void visit(BrowseProduct section) {
System.out.println("浏览商品环节——>" + section.operation(this));
}
@Override
public void visit(Pay section) {
System.out.println("付款环节——>" + section.operation(this));
}
@Override
public void visit(Reviews section) {
System.out.println("评价环节——>" + section.operation(this));
}
}
增加访问者类型:
public class Boss implements Visitor {
@Override
public void visit(BrowseProduct section) {
System.out.println("浏览商品环节——>" + section.operation(this));
}
@Override
public void visit(Pay section) {
System.out.println("付款环节——>" + section.operation(this));
}
@Override
public void visit(Reviews section) {
System.out.println("评价环节——>" + section.operation(this));
}
}
其它不变。