然而現在有個問題是,如果您的集合(connection)物件中不僅儲存一種型態的物件,如果想要對這些物件作出一些個別化的操作,首要條件就是要知道該物件的型態,使用 instanceof 似乎是個不錯的方式,在程式簡單的情況下,也許您會這麼作:
// 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...."); } }
- ElementB.java
public class ElementB implements IElement { public void accept(IVisitor visitor) { visitor.visit(this); } public void operationB() { System.out.println( "do B's job....such-and-such...."); } }
- ElementC.java
public class ElementC implements IElement { public void accept(IVisitor visitor) { visitor.visit(this); } public void operationC() { System.out.println( "do C's job....such-and-such...."); } }
- IVisitor.java
public interface IVisitor { public void visit(ElementA element); public void visit(ElementB element); public void visit(ElementC element); }
- VisitorA.java
public class VisitorA implements IVisitor { public void visit(ElementA element) { element.operationA(); } public void visit(ElementB element) { element.operationB(); } public void visit(ElementC element) { element.operationC(); } }
- 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,就可以換掉所有的操作
// 不用修改多個地方
IVisitor visitor = new VisitorB();
舉個實際的例子,假設VisitorA只是個懶惰的推銷員好了,今天有一個比較勤快的推銷員VisitorB,在訪問過IElement之後,會對 IElement作出更多的操作,要在程式中實現VisitorB,只要增加一個VisitorB類別就可以了:
- VisitorB.java
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 結構類圖如下: