1,概念
访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。
把数据结构和作用于结构上的操作之间解耦,使得操作集合可以相对自由地演化。
1)访问者角色(Visitor):可扩展的。
声明了一个或者多个访问操作,也就是说,该访问者需要做哪些操作;
2)节点角色(Element):固定不变的。
也就是Water这个接口的,它声明一个接受操作,接受一个访问者对象作为一个参量,也就是说,当访问者到来时,需要怎么做。
2,场景
具体操作能够非常稳定的情景下,能够很容易的拓展访问者(Visitor)。eg:JSqlParser框架、stream遍历(内部迭代)。
- 对于一个Visitor,它需要有什么操作,必须要非常清楚;改动成本非常大,如果有新的步骤加入,作为一个导游菜单增强Visitor类。
如下文的例子,招待客人只有茶、咖啡、果汁这3个材料,如果需要增加啤酒就需要增加一个节点类和water实现类,还得在Visitor中加入一个方法,改动所有的Visitor的实现类。 - 增加新的访问者那就非常的简单
多来一个客人,也就是新增加一个新Visitor实现类。
3,UML图
4, 实现
请客人喝茶,每个人口味不同,提前准备好物料。每来一个客人,就抽象一个Visitor的具体实现。
//基本的访问者操作
public interface Visitor {
void visit(TeaWater teaWater);
void visit(JuiceWater juiceWater);
void visit(CaffeeWater caffeeWater);
}
//要喝的东西
public interface Water {
void accept(Visitor visitor);
}
//具体的水:茶、咖啡、果汁,不同类型的水也许会有各自的一些属性操作等等。
public class TeaWater implements Water {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String getHotTea(){
return "热茶";
}
public String getColdTea(){
return "凉茶";
}
}
public class CaffeeWater implements Water {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void addSugar(int number){
System.out.print("添加了"+number+"勺糖");
}
}
public class JuiceWater implements Water {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String getJuice(int size){
return size==0?"小杯":"大杯";
}
}
两个访问者:张三李四。定义visitor的偏好。
public class ZhangsanVisitor implements Visitor{
@Override
public void visit(TeaWater teaWater) {
System.out.print("张三只喝茶,");
String hotTea = teaWater.getHotTea();
System.out.println("拿了"+hotTea);
}
@Override
public void visit(JuiceWater juiceWater) {
//不喜欢果汁,什么操作也不做
}
@Override
public void visit(CaffeeWater caffeeWater) {
//不喜欢咖啡,
}
}
public class LisiVisitor implements Visitor {
@Override
public void visit(TeaWater teaWater) {
System.out.print("能喝点茶");
String coldTea = teaWater.getColdTea();
System.out.println(",拿了"+coldTea);
}
@Override
public void visit(JuiceWater juiceWater) {
System.out.print("也能喝果汁");
String juice = juiceWater.getJuice(1);
System.out.println(",还是要"+juice);
}
@Override
public void visit(CaffeeWater caffeeWater) {
System.out.print("咖啡也要喝,");
caffeeWater.addSugar(2);
}
}
//准备桌子,关联water和visiter
public class Table {
//准备好所有要喝的东西
List waters = new ArrayList<>();
public void addWater(Water water){
waters.add(water);
}
//招待客人
public void accept(Visitor visitor){
for (Water water : waters){
water.accept(visitor);
}
}
}
//具体的使用
@Test
public void test01(){
Table table = new Table();
table.addWater(new TeaWater());//摆上茶
table.addWater(new JuiceWater()); //摆上果汁
table.addWater(new CaffeeWater()); //摆上咖啡
Visitor zhangsan = new ZhangsanVisitor();
Visitor lisi = new LisiVisitor();
System.out.println("张三");
table.accept(zhangsan);
System.out.println("李四");
table.accept(lisi);
}