定義
訪問者模式(Visitor Pattern):表示一個作用於某對象結構中的各個元素操作。訪問者模式讓用戶可以在不改變各元素的類的前提下定義作用於這些元素的新操作。
結構
- Visitor(抽象訪問者):抽象訪問者爲對象結構中的每一個具體元素類聲明一個訪問操作,從這個操作的名稱或參數類型可以清楚地知道需要訪問的具體元素類型,具體訪問者需要實現這些操作方法,定義對這些元素的訪問操作。
- ConcreteVisitor(具體訪問者):具體訪問者實現了每個由抽象訪問者聲明的操作,每一個操作用於訪問對象結構中的一種類型元素。
- Element(抽象元素):抽象元素一般是抽象類或者接口,它聲明瞭一個accept()方法,用於接口訪問者的訪問操作,該方法通常以一個抽象訪問者作爲參數。
- ConcreteElement(具體元素):具體元素實現了accept()方法,在accept()方法中調用訪問者的訪問方法以便完成對一個元素的操作。
- ObjectStructure(對象結構):對象結構是一個元素的集合,它用於存放元素對象,並提供了遍歷其內部元素的方法。對象結構可以結合組合模式來實現,也可以是一個簡單的集合對象。
代碼
Visitor
public abstract class Visitor {
public abstract void visit(ConcreteElementA concreteElementA);
public void visit() {}
}
ConcreteVisitor
public class ConcreteVisitor extends Visitor {
@Override
public void visit(ConcreteElementA concreteElementA) {
}
}
Element
public interface Element {
void accept(Visitor visitor);
}
ConcreteElementA
public class ConcreteElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void operationA() {}
}
ObjectStructure
import java.util.LinkedList;
import java.util.List;
public class ObjectStructure {
private List<Element> list = new LinkedList<>();
public void accept(Visitor visitor) {
for (Element element : list) {
element.accept(visitor); // 遍歷訪問集合中的每一個元素
}
}
public void addElement(Element element) {
list.add(element);
}
public void removeElement(Element element) {
list.remove(element);
}
}
優/缺點與適用環境
- 優點
- 在訪問者模式中增加新的訪問操作很方便。使用訪問者模式,增加新的訪問操作就意昧着增加一個新的具體訪問者類,實現簡單,無須修改源代碼,符合開閉原則。
- 訪問者模式將有關元素對象的訪問行爲集中到一個訪問者對象中,而不是分散在一個個的元素類中。類的職責更加清晰,有利於對象結構中元素對象的複用,相同的對象結構可以供多個不同的訪問者訪問。
- 訪問者模式讓用戶能夠在不修改現有元素類層次結構的情況下定義作用於該層次結構的操作。
- 缺點
- 在訪問者模式中增加新的元素類很困難。在訪問者模式中,每增加一個新的元素類都意味着要在抽象訪問者角色中增加一個新的抽象操作,並在每一個具體訪問者類中增加相應的具體操作,這違背了開閉原則的要求。
- 訪問者模式破壞了對象的封裝性。訪問者模式要求訪問者對象訪問並調用每一個元素對象的操作,這意味着元素對象有時候必須暴露一些自己的內部操作和內部狀態,否則無法供訪問者訪問。
- 適用環境
- 一個對象結構包含多個類型的對象,希望對這些對象實施一些依賴其具體類型的操作。在訪問者中針對每一種具體的類型都提供了一個訪問操作,不同類型的對象可以有不同的訪問操作。
- 需要對一個對象結構中的對象進行很多不同的並且不相關的操作,而需要避免讓這些操作"污染"這些對象的類,也不希望在增加新操作時修改這些類。訪問者模式使得用戶可以將相關的訪問操作集中起來定義在訪問者類中,對象結構可以被多個不同的訪問者類所使用,將對象本身與對象的訪問操作分離。
- 對象結構中對象對應的類很少改變,但經常需要在此對象結構上定義新的操作。