在Java中所有的物件都继承自Object物件,这样作的优点之一,就是使得一些集合物件的资料结构容易管理,例如您可以将任何型态的物件放入Vector中。
然而现在有个问题是,如果您的集合(connection)物件中不仅储存一种型态的物件,如果想要对这些物件作出一些个别化的操作,首要条件就是要知道该物件的型态,使用
instanceof 似乎是个不错的方式,在程式简单的情况下,也许您会这么作:
public class ElementA {
// some implementing
}
public class ElementB {
// some implementing
}
public class ElementC {
// some implementing
}
// ......
Iterator iterator = arrayList.iterator()
while (iterator.hasNext()) {
if (o instanceof
ElementA)
(ElementA) o.operationA();
else if (o
instanceof ElementB)
(ElementB) o.operationB();
else if (o instanceof ElementC)
(ElementC) o.operationC();
else
System.out.println(
"Sorry! I don't know who you are! "
+ o.toString());
//....
}
//....
这么作并不是不可以,只是将来的扩充性不大,如果今天您想要一次改变对每一种类型物件的操作,您必须修改很多地方。
从物件自身的角度来想好了,物件在一个个的房子中,物件说:“不要在房子外费尽心思判断了,即然您不知道我是谁,那么您就进来访问我好了,我告诉您我是谁,这么一来您就知道如何操作我了!”
用程式来实现上面这个描述:
- IElement.java
public interface IElement {
public void accept(IVisitor visitor);
}
- ElementA.java
public class ElementA implements IElement {
public void accept(IVisitor visitor) {
visitor.visit(this);
}
public void operationA() {
System.out.println(
"do A's job....such-and-such....");
}
}
- Main.java
public class Main {
public static void main(String[] args) {
// know nothing about their type
// after storing them into Element array
IElement[] list = {new ElementA(),
new ElementB(),
new ElementC()};
IVisitor visitor = new VisitorA();
for (int i=0; i < list.length; i++)
list[i].accept(visitor);
}
}
Visitor访问是基于overload来完成,对于每一个实现IElement的物件来说,它接受IVisitor来访问它,在accept()方法中,IVisitor使用正确的方法来访问IElement(显然的,这么部份可以靠不同的函式名称,或是overload来达成),并在visit()
中对IElement作出对应的操作,如果您今天想要换掉每一个IElement的操作,只要更换IVisitor类型的物件就可以了,也就是这行:
// IVisitor visitor = new VisitorA();
// 换掉一个IVisitor,就可以换掉所有的操作
// 不用修改多个地方
IVisitor visitor = new VisitorB();
举个实际的例子,假设VisitorA只是个懒惰的推销员好了,今天有一个比较勤快的推销员VisitorB,在访问过IElement之后,会对
IElement作出更多的操作,要在程式中实现VisitorB,只要增加一个VisitorB类别就可以了:
public class VisitorB implements IVisitor {
public void visit(ElementA element) {
System.out.println("VisitorB is a hard worker....");
element.operationA();
System.out.println(
"I want to do some extra work on A....");
}
public void visit(ElementB element) {
System.out.println("VisitorB is a hard worker....");
element.operationB();
System.out.println(
"I want to do some extra work on B....");
}
public void visit(ElementC element) {
System.out.println("VisitorB is a hard worker....");
element.operationC();
System.out.println(
"I want to do some extra work on C....");
}
}
改一下Main来示范:
- Main.java
public class Main {
public static void main(String[] args) {
IElement[] list = {new ElementA(),
new ElementB(),
new ElementC()};
System.out.println("visitorA is coming.......");
IVisitor visitorA = new VisitorA();
for (int i=0; i < list.length; i++)
list[i].accept(visitorA);
System.out.println("\nvisitorB is coming.......");
IVisitor visitorB = new VisitorB();
for (int i=0; i < list.length; i++)
list[i].accept(visitorB);
}
}
在范例中的System.out.println();只是个示意,它也可能是您对IElement的额外方法的直接调用。
Visitor模式的 UML 结构类图如下:
在Java
World中有一篇文章,提到可以利用reflection来改进使用访问者模式时的弹性,有兴趣的可以进一步参考一下Reflect
on the Visitor design pattern。
|