访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式适用于数据结构相对稳定算法又易变化的系统。因为访问者模式使得算法操作增加变得容易。若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者。访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统数据结构。其缺点就是增加新的数据结构很困难。
简单来说,访问者模式就是一种分离对象数据结构与行为的方法,通过这种分离,可达到为一个被访问者动态添加新的操作而无需做其它的修改的效果。
Visitor模式的组成结构:
1) 访问者角色(Visitor):声明一个访问接口。接口的名称和方法的参数标识了向访问者发送请求的元素角色。这样访问者就可以通过该元素角色的特定接口直接访问它。
2) 具体访问者角色(Concrete Visitor):实现访问者角色(Visitor)接口
3) 元素角色(Element):定义一个Accept操作,它以一个访问者为参数。
4) 具体元素角色(Concrete Element):实现元素角色(Element)接口。
5) 对象结构角色(Object Structure):这是使用Visitor模式必须的角色。它要具备以下特征:能枚举它的元素;可以提供一个高层的接口允许访问者角色访问它的元素;可以是一个组合(组合模式)或是一个集合,如一个列表或一个无序集合。
示例:
假设一个火星人和一个地球人都要对美国和俄罗斯进行国事访问(其实是去玩),那么他们就是包含visit方法的访问者;美国和俄罗斯碍于情面也只得接待他们,于是两个国家就是包含accept方法的具体元素。
对火星人与地球人进行抽象,他们都是访问者,于是定义Visitor接口:
public interface Visitor {
/**
* 对美国进行访问
* @param america
*/
public void visit(America america);
/**
* 对俄罗斯进行访问
* @param russia
*/
public void visit(Russia russia);
}
火星人实现类:
/**
* 火星人
*/
public class Martian implements Visitor {
@Override
public void visit(America america) {
System.out.println(this.toString() + ", 我去看过" + america.getViewSpots());
}
@Override
public void visit(Russia russia) {
System.out.println(this.toString() + ", 我太忙了,先回去了,下次再来看!");
}
@Override
public String toString() {
return "火星人-访问者";
}
}
地球人实现类:
/**
* 地球人
*/
public class Earthman implements Visitor {
@Override
public void visit(America america) {
System.out.println(this.toString() + ", 我去看过" + america.getViewSpots());
}
@Override
public void visit(Russia russia) {
System.out.println(this.toString() + ", 我去看过" + russia.getViewSpots());
}
@Override
public String toString() {
return "地球人-访问者";
}
}
对美国和俄罗斯进行抽象,他们都是有很多旅游景点的国家,都要对来参观的人进行接待,于是定义Country接口:
public interface Country {
/**
* 对访问者进行接待
* @param visitor
*/
public void accept(Visitor visitor);
/**
* 列举旅游景点
*/
public String getViewSpots();
}
public class America implements Country {
public void accept(Visitor visitor) {
System.out.println("欢迎"+visitor + "光临美国!");
visitor.visit(this);
}
@Override
public String getViewSpots() {
return "白宫,好莱坞,阿拉斯加";
}
}
俄罗斯实现类:
public class Russia implements Country {
@Override
public void accept(Visitor visitor) {
System.out.println("欢迎"+visitor + "光临俄罗斯!");
visitor.visit(this);
}
@Override
public String getViewSpots() {
return "克里姆林宫, 贝加尔湖, 红场";
}
}
测试类:
public class Test {
public static void main(String[] args) {
//火星人与地球人开始对美国和俄罗斯进行访问
Visitor martian = new Martian();
Visitor earthman = new Earthman();
Country america = new America();
Country russia = new Russia();
// 美国进行接待
america.accept(martian);
america.accept(earthman);
// 俄罗斯进行接待
russia.accept(martian);
russia.accept(earthman);
}
}