访问者模式(Visitor)
Java深入到一定程度,就不可避免的碰到设计模式这一概念,了解设计模式,将使自己对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统中应用广泛,遵循一定的编程模式,才能使自己的代码便于理解,易于交流,Visitor(访问者)模式是比较常用的一个模式.
应用场景:对于某对象结构中各元素的操作。如果需要在不修改各元素类的前提下定义作用于这些元素的新操作,也就是动态的增加新的方法应该考虑访问者模式。
想让数个不同的访问者对同一个对象集合进行访问时,Visitor模式可以发挥它的强大作用。Visitor先调用了Visitable类中的方法,这个方法又回调到Visitor类中
在此写了10个java类来描述说明Visitor设计模式;
1、 NodeA.java 可访问节点A
2、 NodeB.java 可访问节点B
3、 NodeC.java 可访问节点C
4、 Visitable.java 可访问对象接口
5、 Visitor.java 访问者接口
6、 VisitorA.java 访问者A
7、 VisitorTest.java 带有main方法的测试类
5变体、 Visitor.java 访问者接口(应用java反射机制)
6变体、 VisitorA.java 访问者A(应用java反射机制)
7变体、 VisitorTest.java 带有main方法的测试类(应用java反射机制)
=============== 1、 NodeA.java
package visitor;
public class NodeA implements Visitable {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
=============== 1 end
=============== 2、 NodeB.java
package visitor;
public class NodeB implements Visitable {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
=============== 2 end
=============== 3、 NodeC.java
package visitor;
public class NodeC implements Visitable {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
=============== 3 end
=============== 4、 Visitable.java
package visitor;
public interface Visitable {
public void accept(Visitor visitor);
}
=============== 4 end
=============== 5、 Visitor.java
package visitor;
import java.util.Collection;
public interface Visitor {
//访问节点A
public void visit(NodeA nodeA);
//访问节点B
public void visit(NodeB nodeB);
//访问节点C
public void visit(NodeC nodeC);
//访问节点集合
public void visitCollection(Collection collection);
}
=============== 5 end
=============== 6、 VisitorA.java
package visitor;
import java.util.Collection;
import java.util.Iterator;
public class VisitorA implements Visitor {
public void visit(NodeA a){
System.out.println("Execute visitNodeA method!");;
}
public void visit(NodeB b){
System.out.println("Execute visitNodeB method!");;
}
public void visit(NodeC c){
System.out.println("Execute visitNodeC method!");;
}
public void visitCollection(Collection collection){
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
Object o = iterator.next();
if (o instanceof Visitable)
((Visitable)o).accept(this);
}
}
}
=============== 6 end
=============== 7、 VisitorTest.java
package visitor;
import java.util.ArrayList;
import java.util.List;
public class VisitorTest {
public static void main(String[] args) {
NodeA nodeA = new NodeA();
NodeB nodeB = new NodeB();
NodeC nodeC = new NodeC();
VisitorTest nodeD = new VisitorTest();
//访问单个对象
VisitorA visitorA = new VisitorA();
visitorA.visit(nodeA);
visitorA.visit(nodeB);
visitorA.visit(nodeC);
//访问集合
List
list.add(nodeA);
list.add(nodeB);
list.add(nodeC);
visitorA.visitCollection(list);
}
}
=============== 7 end
在两个接口Visitor和Visitable中,确保Visitable很少变化,也就是说,确保不能老有新的Element元素类型加进来,可以变化的是访问者行为或操作,也就是Visitor的不同子类可以有多种,这样使用访问者模式最方便.
当然采用java反射机制, 可以使对象集合中的对象经常有变化。
采用java反射机制的 Visitor 变体
采用了java反射机制的vistor变体,类1,2,3,4 均不变
通过使用Java Reflection,可以增强Visitor模式,使之具有操作对象结构的强大功能,并在增加新Visitable类型方面提供灵活性。
=============== 5变体、 Visitor.java
package visitor;
public interface Visitor {
//访问者触发的方法
public void visit(Object o);
}
=============== 5变体 end
=============== 6变体、 VisitorA.java
package visitor;
import java.lang.reflect.Method;
import java.util.AbstractCollection;
import java.util.Iterator;
public class VisitorA implements Visitor {
public void visitObject(Object o) {
System.out.println("Execute visitObject method!");;
}
public void visitNodeA(NodeA a){
System.out.println("Execute visitNodeA method!");;
}
public void visitNodeB(NodeB b){
System.out.println("Execute visitNodeB method!");;
}
public void visitNodeC(NodeC c){
System.out.println("Execute visitNodeC method!");;
}
public void visitAbstractCollection(AbstractCollection
Iterator
while(iterator.hasNext()){
iterator.next().accept(this);
}
}
//对o元素进行访问
public void visit(Object o){
try {
//1 Get the method of visitor needed to call
Method m = getMethod(o.getClass());
//2 execute the method
m.invoke(this, new Object[]{o});
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
//根据传进来的类名获得访问者需要执行的方法
protected Method getMethod(Class c) {
Class newc = c;
Method m = null;
//根据传进来的类名去寻找相应的方法,如果不从在就去超类中找
String method = null;
while (m == null && newc != Object.class) {
method = "visit" + newc.getSimpleName();
try {
m = getClass().getMethod(method, new Class[] {newc});
} catch (NoSuchMethodException e) {
newc = newc.getSuperclass();
}
}
//如果超类是Object,则到接口中找
if (newc == Object.class) {
Class[] interfaces = c.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
method = "visit" + interfaces[i].getSimpleName();
try {
m = getClass().getMethod(method, new Class[] {interfaces[i]});
} catch (NoSuchMethodException e) {}
}
}
//如果m==null,则执行visitor中默认的方法
if (m == null) {
try {
m = this.getClass().getMethod("visitObject", new Class[] {Object.class});
} catch (Exception e) {}
}
return m;
}
}
=============== 6变体 end
=============== 7变体、 VisitorTest.java
package visitor;
import java.util.ArrayList;
import java.util.List;
public class VisitorTest {
public static void main(String[] args) {
NodeA nodeA = new NodeA();
NodeB nodeB = new NodeB();
NodeC nodeC = new NodeC();
VisitorTest nodeD = new VisitorTest();
//访问单个对象
VisitorA visitorA = new VisitorA();
visitorA.visit(nodeA);
visitorA.visit(nodeB);
visitorA.visit(nodeC);
visitorA.visit(nodeD);
//访问集合
List
list.add(nodeA);
list.add(nodeB);
list.add(nodeC);
visitorA.visit(list);
}
}
=============== 7变体 end