浅谈Visitor Pattern
第一步: 在介绍Visitor Pattern (访问者模式)之前,先简要介绍一下:双重分派。
在Visitor Pattern中双重分派是指:数据结构的每一个节点都可以接受一个访问者的调用(这句话的代码是:在具体的节点类中有形如如下的方法accept(Visitor visitor){visitor.visitor(this)},说白一点就是,在节点类中有一个方法,以访问者作为参数,这个访问者也就是Visitor接口),此节点向访问者对象传入节点对象,而访问者对象反过来执行节点对象的操作。(这句话的代码是:在具体的访问者类中,有形如一个visitor(ConcreteNode node){node.operation()}的方法,说白点就是在Visitor接口中有益具体节点为参数的方法,有几个具体节点,就有几个方法)这样的过程就叫做双重分派。
第二步:介绍访问者模式所涉及的角色:
访问者模式的角色有6个,分别是:Visitor(抽象访问者) 、ConcreteVisitor(具体访问者)、Node(抽象节点),ConcreteNode(具体节点)、ObjectStructure(结构对象,你也可以翻译为对象结构,其实我更喜欢对象结构。)Client(客户,相当于一个测试类)
第三步:代码示例,把各个角色的代码抽象出来。
Visitor(抽象访问者)是一个接口或者,抽象类,其代码如下:
package com.qls.visitorPattern5;
public interface Visitor {
/**
* NodeA,NodeB分别是Node接口的两个具体实现类,
* 由于本例展示两个Node的具体实现类,所以Visitor接口中的抽象方法只有两个
* 一般而言:有多少个具体节点的实现类,在Visitor接口中就有多少个抽象方法。
* 这是因为:每一个具体的节点都有独一无二的业务方法(business method).
* @param node
*/
void visitor(NodeA node);
void visitor(NodeB node);
}
ConcreteVisitor(具体访问者)是Visitor的实现类,其代码如下:
第一个具体访问者的代码如下:
package com.qls.visitorPattern5;
public class VisitorA implements Visitor {
@Override
public void visitor(NodeA node) {
// TODO Auto-generated method stub
node.operation();//这个operation()是NodeA的特有的业务方法
}
@Override
public void visitor(NodeB node) {
// TODO Auto-generated method stub
node.operation();//这个operation()是NodeB的特有的业务方法
}
}
第二个具体访问者的代码如下:
package com.qls.visitorPattern5;
public class VisitorB implements Visitor {
@Override
public void visitor(NodeA node) {
// TODO Auto-generated method stub
node.operation();
}
@Override
public void visitor(NodeB node) {
// TODO Auto-generated method stub
node.operation();
}
}
Node(抽象节点)是一个接口,或者抽象类。是所有具体节点的基类.
package com.qls.vistitorPattern3;
/**
* 在Node接口中有以Visitor(抽象访问者)为参数的方法
* @author 秦林森
*
*/
public interface Node {
void accept(Visitor visitor);
}
ConcreteNode(具体节点)本例中有两个具体节点。
第一个具体节点的代码如下:
package com.qls.vistitorPattern3;
public class NodeA implements Node {
@Override
public void accept(Visitor visitor) {
// TODO Auto-generated method stub
/**
* 这个this指代NodeA,其检验方法为:
* System.out.println("this 所指代的类是:"+this.getClass());
当我们不确定this,指代谁时,可以用这种方法进行检测。
*/
visitor.visitor(this);
}
//NodeA 所特有的业务方法或者称为商业方法
void operation(){
System.out.println("this is nodeA's operation");
}
}
第二个具体节点的代码如下:
package com.qls.vistitorPattern3;
public class NodeB implements Node {
/**
* 表示接受一个访问者。进行访问这个节点NodeB,执行NodeB所特有的业务方法。
*/
@Override
public void accept(Visitor visitor) {
// TODO Auto-generated method stub
visitor.visitor(this);
}
//NodeB 所特有的业务方法或者称为商业方法
void operation(){
System.out.println("this is nodeB's operation");
}
}
ObjectStructure(结构对象),这个角色的作用,以我个人的理解就是建立Visitor和Node关系的一个类。
其代码如下:
package com.qls.visitorPattern5;
import java.util.Enumeration;
import java.util.Vector;
public class ObjectStructure {
/**
* 一个容器用来存放Node,这个容器可以是ArrayList,Set等等不一定就非是Vector不可
*/
private Vector<Node> nodes;
private Node node;
public ObjectStructure() {
nodes=new Vector<Node>();
}
public void action(Visitor visitor){
Enumeration<Node> e = nodes.elements();
while(e.hasMoreElements()){
node = e.nextElement();
node.accept(visitor);//接受访问者,让访问者执行具体节点的相关操作。
}
}
/**
* 添加节点
* @param args
*/
public void add(Node node){
nodes.addElement(node);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
Client(客户)其作用就相当于一个测试类,把各个具体节点的业务方法的结果打印出来。
其代码如下:
package com.qls.visitorPattern5;
public class Client {
private static ObjectStructure objectStructure;
// private static Visitor visitor;
// private static Node node;
public static void main(String[] args) {
// TODO Auto-generated method stub
objectStructure=new ObjectStructure();//这步必须写,后者会报NullPointException
//添加一个节点
objectStructure.add(new NodeA());
objectStructure.add(new NodeB());
//创建一个访问者
objectStructure.action(new VisitorA());
//创建一个访问者
objectStructure.action(new VisitorB());
}
}
上述代码的运行结果为:由于我让两个访问者去访问ObjectStructure,具体节点的操作,是由具体访问者代劳的,所以运行结果为:
//前两句话是由objectStructure.action(new VisitorA());所产生的。
//后两句话是由:objectStructure.action(new VisitorB());所产生的。
this is nodeA's business method
this is NodeB's business method
this is nodeA's business method
this is NodeB's business method