访问者模式是一种将算法与对象结构分离的软件设计模式。这种模式的工作方法如下:假设拥有一个由许多对象构成的对象结构,这些对象的类都拥有一个accept方法用来接受访问者对象;访问者是一个接口,它拥有一个visit方法,这个方法对访问到的对象结构中不同类型的元素做出不同的反应;在对象结构的一次访问过程中,遍历整个对象结构,对每个元素都实施accept方法,在每个元素的accept方法中回调访问者的visit方法,从而使访问者得以处理对象结构的每个元素;可以针对对象结构设计不同的具体访问者类来完成不同的操作。
这里通过一个实际场景来介绍访问者模式:假设某旅游爱好者决定在假期去北京、上海和深圳旅游,在每个城市都会进行一些不同的活动,需要通过访问者模式来实现。
总的设计方案如下图所示。
首先,针对不同城市抽象出一个City接口。每个城市都通过accept方法接受访问者,其中Visitor表示访问人员的接口。
public interface City {
public void accept(Visitor visitor);
}
接着,创建具体的城市实体类,包括上述3个城市。每个城市的accept实现完全相同,调用访问者接口中实现的visit方法进行对应的活动。
public class Beijing implements City {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class Shanghai implements City {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class Shenzhen implements City {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
将上述3个城市整合在旅游计划中。此外,用TravelCities类实现City的接口,在accept中对初始化构造的城市列表依次进行访问。
public class TravelCities implements City {
City[] cities;
public TravelCities(){
cities = new City[]{new Beijing(),new Shanghai(),new Shenzhen()};
}
@Override
public void accept(Visitor visitor) {
for(int i=0; i<cities.length; i++){
cities[i].accept(visitor);
}
}
}
然后,定义访问者Visitor接口。需要注意,在该接口中包含访问所有城市的visit方法,分别代表该访问者在不同城市的具体活动。
public interface Visitor {
public void visit(Beijing beijing);
public void visit(Shanghai shanghai);
public void visit(Shenzhen shenzhen);
}
假设旅行者是一个人出行,这里实现一个SingleVisitor类,代表该旅行者在不同城市所进行的活动。
public class SingleVisitor implements Visitor {
@Override
public void visit(Beijing beijing) {
System.out.println("Hello Beijing!");
}
@Override
public void visit(Shanghai shanghai) {
System.out.println("Hello Shanghai!");
}
@Override
public void visit(Shenzhen shenzhen) {
System.out.println("Hello Shenzhen!");
}
}
最后,通过一个Demo类来执行整个流程。
public class Demo {
public static void main(String[] args) {
TravelCities travelCities = new TravelCities();
travelCities.accept(new SingleVisitor());
}
}
上述案例使用访问者模式把结构和行为分离,如果需要多增加行为,则添加新的Visitor或重载已有的Visitor并修改特定的访问行为。