定义
表示一个作用于某对象结构中各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
关键字
操作分离——将一个类中操作与这个类进行分离,在不改变这个类的前提下可以定义新的操作。
对象结构——访问者模式适用于对象结构,而不是某个单独的对象。对象结构可以理解为一个对象集合,里面存储了一堆的对象。
适用性
1,一个对象结构中包含很多类对象,它们有不同的接口,但想对这些对象定义一些依赖于其具体类的操作。此时使用访问者模式可以避免对对象结构中每一个对象类型进行判断。如:
private void visitorMode() {
List<IDemo> objs = new ArrayList<>(); //数据结构——其中
objs.add(new Demo1("DEMO1"));
objs.add(new Demo2("DEMO2"));
MyVisitor v = new MyVisitor();
for (IDemo demo : objs) {
demo.accept(v);
}
}
private class MyVisitor implements IVisitor {
@Override
public void visitDemo1(Demo1 demo1) {//对结构中的每一个类定义一个方法,由具体的类决定自己调用访问者中的哪一个访问,同时将自身作为参数传入相应的方法中
Log.e(TAG, demo1.getName());
}
@Override
public void visitDemo2(Demo2 demo2) {
Log.e(TAG, demo2.getName());
}
}
这里的IDemo只是定义了accept()操作。对于Demo1与Demo2类完全可以有自己的属性与方法。而且访问者中visitDemo1与visitDemo2完全可以根据传入的参数获取相应的数据,然后进行不同的操作。
任意一个accept()的简单实现如下:
public void accept(IVisitor visitor) {
visitor.visitDemo1(this);//直接将操作转给访问者
}
2,需要对一个对象结构中的对象进行很多不同且不相关的操作,而且避免让这些操作污染这些对象的类——也就是说不想将操作定义在各自的对象的类中。此时使用访问者模式,将这些操作与类分离出来,并将这些操作定义在一个单独的类中。
同时,当这个对象结构被多个应用共享时,各个应用可以根据自己的需要定义自己的访问者——也就是定义自己的操作。完全不需要修改类的代码。
如上面的代码中, 完全可以重新定义一个访问者,达到对对象结构中对象的不同操作。
3,对象结构中的类很少改变——注意:不是对象很少改变,是对象的类很少改变——但是需要经常在此结构上定义新的操作。改变对象结构的类,就需要重新定义所有的访问者——因为每一个访问者都需要添加一个对应新类的方法,这种代价是很大的。因此,如果对象结构的类经常变化,不可以使用访问者模式,需要将各种操作定义在类中。
参与者
Visitor:抽象访问者,为每一个具体类定义一个方法。理论上讲,它里面的方法的个数与类的个数一致。因此,如果类族不稳定,经常需要添加、删除类,那么绝对不适合访问者模式。
ConcreteVisitor:具体访问者,每一个方法会根据传入的参数决定当前访问的类。
Element:元素,定义一个accept()方法,会以Visitor为参数。
ConcreteElement:具体元素,实现accept()方法。同时它也要提供方法,以便访问者能获取自己需要的数据。
ObjectStructure:对象结构。1,能枚举它的元素;2,提供一个高层的接口以允许该访问者访问它的元素;3,可以是一个组合对象或一个集合。
效果
1,易于增加新的操作。新添加一个访问者,就可以为对象结构中的所有对象定义新的操作。
2,操作集中。相关行为不是定义在各个类中,而是集中在一个访问者中。这样的有利于各个类之间状态累积。
3,累积状态。当访问者访问对象结构中的每一个元素时,可以累积状态。而不使用访问者时,这些状态需要做为额外的参数进行传递或者定义成全局变量。如:
private void visitorMode() {
List<IDemo> objs = new ArrayList<>(); //数据结构——其中
objs.add(new Demo1("DEMO1"));
objs.add(new Demo2("DEMO2"));
MyVisitor v = new MyVisitor();
for (IDemo demo : objs) {
demo.accept(v);
}
Log.e(TAG, "visitor result = " + v.getName());
}
private class MyVisitor implements IVisitor {
private String name = "";
@Override
public void visitDemo1(Demo1 demo1) {
name += demo1.getName();
}
@Override
public void visitDemo2(Demo2 demo2) {
name += demo2.getName();
}
public String getName() {
return name;
}
}
上述直接在访问者中记录了每一个对象的name属性——此即累积状态。
4,破坏封装。访问者迫使对象往外提供一些方法,以便访问者可以获取自己需要的数据。