VISITOR访问者
1、 意图
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
2、 适用性
在下列情况下使用visitor模式:
- 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
- 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作教好。
3、 结构
4、 参与者
Visitor(访问者)
——为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请求给该访问者的那个类。这使得访问者可以确定正被访问元素的具体类。这样访问者就可以通过该元素的特定接口直接访问它。
ConcreteVisitor(具体访问者)
——实现每个由Visitor声明的操作。每个操作实现本算法的一部分,而该算法片段是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中积累的结构。
Element(元素)
——定义一个Accept操作,它以一个访问者为参数。
ConcreteElement(具体元素)
——实现Accept操作,该操作以一个访问者为参数。
ObjectStruccture(对象结构)
——能枚举它的元素。
——可以提供一个高层的接口以允许该访问者访问它的元素。
——可以是一个复合。
5、 协作
1) 一个使用Visitor模式的客户必须创建一个ConcreteVisitor对象,然后遍历该对象结构,并用该访问者访问每一个元素。
2) 当一个元素被访问时,它调用对应于它的类的Visitor操作。如果必要,该元素将自身作为这个操作的一个参数以便该访问者访问它的状态。
6、 效果
1) 访问者模式使得易于增加新的操作。
2) 访问者集中相关的操作而分离无关的操作。
3) 增加新的ConcreteElement类很难。Visitor模式使得难以增加新的Element的子类。每添加一个新的ConcreteElement都要在Visitor中添加一个新的抽象操作,并在每一个ConcreteVisitor类中实现相应操作。
4) 通过类层次进行访问。
5) 积累状态。当访问者访问对象结构中的每一个元素时,它可能会累积状态。如果没有访问者,这一状态将作为额外的参数传递给进行遍历的操作,或者定义为全局变量。
6) 破坏封装。
7、 实现
1) 双分派。访问者模式允许你不改变类即可有效地增加其上的操作。为达到这一效果使用了双分派(double-dispatch)的技术。双分派意味着得到执行的操作决定于请求的种类和两个接收者的类型。Accept是一个double-dispatch操作。它的含义决定于两个类型:Visitor的类型和Element的类型。双分派使得访问者可以对每一个类元素请求不同的操作。
这是Visitor模式的关键所在:得到执行的操作不仅决定于Visitor的类型还决定于它访问的Element的类型。可以不将操作静态地绑定在Element接口中,而将其安放在一个Visitor中,并使用Accept在运行时进行绑定。扩展Element接口就等于定义一个新的Visitor子类而不是多个新的Element子类。
2) 谁负责遍历对象结构。一个访问者必须访问这个对象结构的每一个元素。我们可以将遍历的责任放到下面三个地方中的任意一个:对象结构中,访问者中,或一个独立的迭代器对象中。通常由对象结构负责迭代。一个集合只需对它的元素进行迭代,并对每一个元素调用Accept操作。而一个复合通常让Accept操作遍历该元素的各子构件并对它们中的每一个递归调用Accept。
另一种解决方案就是使用一个迭代器来访问各个元素。
8、 代码示例
Visitor
package com.examples.pattern.visitor;
/**
* 访问者接口
*/
public interface Visitor {
/**
* 访问元素A,相当于给元素A添加访问者的功能。
* @param elementA 元素A的对象
*/
public void visitConcreteElementA(ConcreteElementA elementA);
/**
* 访问元素B,相当于给元素B添加访问者的功能。
* @param elementB 元素B的对象
*/
public void visitCOncreteElementB(ConcreteElementB elementB);
}
ConcreteVisitor
package com.examples.pattern.visitor;
/**
* 具体访问者的实现
*/
public class ConcreteVisitorA implements Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA elementA) {
//把要访问ConcreteElementA时,需要执行得到功能实现在这里
//可能需要访问元素已有的功能。
elementA.opertionA();
}
@Override
public void visitCOncreteElementB(ConcreteElementB elementB) {
elementB.opertionB();
}
}
package com.examples.pattern.visitor;
/**
* 具体访问者的实现
*/
public class ConcreteVisitorB implements Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA elementA) {
// 把要访问ConcreteElementA时,需要执行得到功能实现在这里
// 可能需要访问元素已有的功能。
elementA.opertionA();
}
@Override
public void visitCOncreteElementB(ConcreteElementB elementB) {
elementB.opertionB();
}
}
Element
package com.examples.pattern.visitor;
/**
* 被访问的元素的接口
*/
public abstract class Element {
/**
* 接受访问者的访问
* @param visitor 访问者对象
*/
public abstract void accept(Visitor visitor);
}
ConcreteElement
package com.examples.pattern.visitor;
/**
* 具体元素的实现
*/
public class ConcreteElementA extends Element {
@Override
public void accept(Visitor visitor) {
//回调访问者对象的相应方法
visitor.visitConcreteElementA(this);
}
public void opertionA(){
System.out.println("this is operation A");
}
}
package com.examples.pattern.visitor;
/**
* 具体元素的实现对象
*/
public class ConcreteElementB extends Element {
@Override
public void accept(Visitor visitor) {
//回调访问者对象的相应方法
visitor.visitCOncreteElementB(this);
}
public void opertionB(){
System.out.println("this is operation B");
}
}
ObjectStruccture
package com.examples.pattern.visitor;
import java.util.ArrayList;
import java.util.Collection;
/**
* 对象结构,通常在这里对元素对象进行遍历,让访问者能访问到所有的元素
*/
public class ObjectStructure {
/**
* 示意,表示对象结构。可以是一个组合结构或是集合。
*/
private Collection<Element> col = new ArrayList<Element>();
/**
* 提供给客户端操作的高层接口
* @param visitor 客户端需要使用的访问者
*/
public void handleRequest(Visitor visitor){
//循环对象结构中的元素,接受访问
for(Element ele : col){
ele.accept(visitor);
}
}
/**
* 组件对象结构,向对象结构中添加元素
* @param ele 加入到对象结构的元素
*/
public void addElement(Element ele){
this.col.add(ele);
}
}
Client
package com.examples.pattern.visitor;
public class Client {
public static void main(String[] args) {
//创建ObjectStruccture
ObjectStructure os = new ObjectStructure();
//创建要加入对象结构的元素
Element eleA = new ConcreteElementA();
Element eleB = new ConcreteElementB();
//把元素加入对象结构
os.addElement(eleA);
os.addElement(eleB);
//创建访问者
Visitor visitor = new ConcreteVisitorA();
os.handleRequest(visitor);
}
}
9、 相关模式
Composite:访问者可以用于对一个由Composite模式定义的对象结构进行操作。
Interpreter:访问者可以用于解释。