访问者模式(Visitor),是一种行为性模型,行为型模式关注的是系统中对象之间的相互交互,解决系统在运行时对象之间的相互通信和协作,进一步明确对象的职责。相比来说,创建型模式关注对象的创建过程,结构型模式关注对象和类的组合关系。
模式的职责
对于存储在一个集合中的对象,他们可能具有不同的类型(即使有一个公共的接口),对于该集合中的对象,可以接收一类成为访问者的对象来访问,不同的访问者其访问方式也有所不同。
表示一个作用于某对象结构中的各元素的操纵它使我们可以在不改变个元素的来的前提下定义作用于这些元素的新操作。
模式的使用场景
XML文档解析器设计
表一起的设计
复杂集合对象的处理
模式的结构
抽象访问者:对访问者的抽象,声明访问者可以访问那些元素。
访问者:实现抽象访问者中的访问方法,它影响到访问者访问到一个类后该做什么,要做什么。
抽象元素类:对元素类的抽象,声明接受哪一类访问者访问。
元素类:实现对于抽象的实现,一般是定式vistor vistor(this)。
结构对象:一个元素的容器,一般可以包含不同类,不同接口的容器
模式的实现
//元素抽象类
public interface Element {
//元素接收访问者访问的方法
void accept(Victor vister);
//元素能执行的方法
void elementCando();
}
//元素的具体实现
class Element1 implements Element{
//接收访问者访问的方法
public void accept(Victor vister) {
vister.visit(this);
}
//该元素本身的逻辑和方法(可以有很多)
public void elementCando() {
System.out.println("我是元素1,这是我的方法");
}
}
//元素的具体实现
class Element2 implements Element{
//接收访问者访问的方法
public void accept(Victor vister) {
vister.visit(this);
}
//该元素本身的逻辑和方法(可以有很多)
public void elementCando() {
System.out.println("我是元素2,这是我的方法");
}
}
//访问这的抽象类
public interface Victor {
//对于元素1的访问
void visit(Element1 e1);
//对于元素2的访问
void visit(Element2 e2);
}
class VictorImp implements Victor{
//对于元素1访问的具体实现
public void visit(Element1 e1) {
System.out.println("我在vistit中可以调用元素1啦!那我就直接用");
e1.elementCando();
}
//对于元素2访问的具体实现
public void visit(Element2 e2) {
System.out.println("我在vistit中可以调用元素2啦!那我就直接用");
//具体调用的方法可以用其他方法实现
e2.elementCando();
}
}
class VictorImpement implements Victor{
//对于元素1访问的具体实现
public void visit(Element1 e1) {
System.out.println("我在vistit中可以调用元素1啦!我先不用");
}
//执行元素1的方法的方式
public void doElement1(Element1 e1){
e1.elementCando();
}
//对于元素2访问的具体实现
public void visit(Element2 e2) {
System.out.println("我在vistit中可以调用元素2啦!我先不用");
//具体调用的方法可以用其他方法实现
}
//执行元素2的方法的方式
public void doElement2(Element2 e2){
e2.elementCando();
}
}
//结构对象,用来管理访问者和元素类之间的关系
public class ObjectStructure {
//用来记录元素的对象
private List<Element>list = new ArrayList<Element>();
//登记元素的对象
public void add(Element e){
list.add(e);
}
//让已经登记元素接收访问者的访问
public void action(Victor v){
//可以全部接受,也可以由逻辑判断选择性的接受
for(Element e:list){
e.accept(v);
}
}
}
//客户端调用
public class Client {
public static void main(String[] args) {
//创建结构的对象
ObjectStructure o = new ObjectStructure();
//创建元素的对象
Element1 e1 = new Element1();
Element2 e2 = new Element2();
//结构对象中登记元素对象
o.add(e1);
o.add(e2);
//创建访问者对象
Victor v1 = new VictorImp();
Victor v2 = new VictorImpement();
//在创建结构中让访问者可以访问所有元素
o.action(v1);
o.action(v2);
//访问者注册了访问方法调用分离的调用(其实一般都怎么做)
v2.visit(e1);
v2.visit(e2);
}
}
模式的优缺点
优点
扩展性好:能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
复用性好:可以通过访问者来定义整的对象结构通用的功能,从而提高复用程度。
分离无关行为:可以通过访问者来分离无关的行为,把相关的行为封装在一起,构成一个访问者,这样每一个访问者的功能都比较单一。
缺点
对象结构变化很困难:对象结构一旦发送改变,访问者的接口和访问者的实现都要发生相应的改变,代价太高。
破坏封装:访问者模式通常要对象接口发放内部数据给访问者和对象结构类,这破坏了对象的封装性。