Visitor定義:作用於某個對象群中各個對象的操作。它可以使你在不改變這些對象本身的情況下,定義作用於這些對象的新操作。
在Java中,Visitor模式實際上是分離了collection結構中的元素和對這些元素進行操作的行為。
Java的Collection(包括Vector和Hashtable)是我們最經常使用的技術,可是Collection好象是個黑色大染缸,本來有各種鮮明類型特征的對象一旦放入後,再取出時,這些類型就消失了。那麼我們勢必要用If來判斷,如:
Iterator iterator = collection.iterator() while (iterator.hasNext()) { Object o = iterator.next(); if (o instanceof Collection) messyPrintCollection((Collection)o); else if (o instanceof String) System.out.println("'"+o.toString()+"'"); else if (o instanceof Float) System.out.println(o.toString()+"f"); else System.out.println(o.toString()); }
在上例中,我們使用了 instanceof來判斷 o的類型。
很顯然,這樣做的缺點代碼If else if 很繁瑣,我們就可以使用Visitor模式解決它。
針對上例,我們設計一個接口visitor訪問者:
public interface Visitor { public void visitCollection(Collection collection); public void visitString(String string); public void visitFloat(Float float); }
在這個接口中,將我們認為Collection有可能的類的類型放入其中。
有了訪問者,我們需要被訪問者,被訪問者就是我們Collection的每個元素Element,我們要為這些Element定義一個可以接受訪問的接口(訪問和被訪問是互動的,只有訪問者,被訪問者如果表示不歡迎,訪問者就不能訪問)。
我們定義這個接口叫Visitable,用來定義一個Accept操作,也就是說讓Collection每個元素具備可訪問性。
public interface Visitable{ public void accept(Visitor visitor); }
好了,有了兩個接口,我們就要定義他們的具體實現(Concrete class):
public class ConcreteElement implements Visitable { private String value; public ConcreteElement(String string) { value = string; } //定義accept的具體內容 這裡是很簡單的一句調用 public void accept(Visitor visitor) { visitor.visitString(this); } }
再看看訪問者的Concrete實現:
public class ConcreteVisitor implements Visitor { //在本方法中,我們實現了對Collection的元素的成功訪問 public void visitCollection(Collection collection) { Iterator iterator = collection.iterator() while (iterator.hasNext()) { Object o = iterator.next(); if (o instanceof Visitable) ((Visitable)o).accept(this); } public void visitString(String string) { System.out.println("'"+string+"'"); } public void visitFloat(Float float) { System.out.println(float.toString()+"f"); } }
在上面的visitCollection我們實現了對Collection每個元素訪問,只使用了一個判斷語句,只要判斷其是否可以訪問。
至此,我們完成了Visitor模式基本架構。
對象群結構中(Collection) 中的對象類型很少改變,也就是說訪問者的身份類型很少改變,如上面中Visitor中的類型很少改變,如果需要增加新的操作,比如上例中我們在ConcreteElement具體實現外,還需要新的ConcreteElement2 ConcreteElement3。
可見使用Visitor模式是有前提的,在兩個接口Visitor和Visitable中,確保Visitor很少變化,變化的是Visitable,這樣使用Visitor最方便。
如果Visitor也經常變化,也就是說,對象群中的對象類型經常改變,一般建議是,不如在這些對象類中逐個定義操作,但是Java的Reflect技術解決了這個問題。