定義
提供一個作用於某物件結構中的各元素的操作表示,它使我們可以在不改變各元素的類的前提下定義作用於這些元素的新操作。
設計的原則和思想
- 物件(穩定的資料結構)與操作(易變的操作)解耦
- 不變部分是物件的資料結構,變化部分是操作。
- 核心思想是同樣一件事,不同的人有不同的做法。
一句話概括設計模式
透過訪問者去操作物件的行為。
結構中包含的角色
- Vistor(抽象訪問者)
- ConcreteVisitor(具體訪問者)
- Element(抽象元素)
- ConcreteElement(具體元素)
- ObjectStructure(物件結構)
最小可表達程式碼
abstract class Visitor
{
public abstract function visit(Element $element);
}
class ConcreteVisitor extends Visitor
{
public function visit(Element $element)
{
echo "訪問者具體業務";
}
}
interface Element
{
public function accept(Visitor $visitor);
}
class ConcreteElement implements Element
{
public function accept(Visitor $visitor)
{
$visitor->visit($this);
}
}
class ObjectStructure
{
private $elements = [];
public function add(Element $element)
{
$this->elements[] = $element;
}
public function accept(Visitor $visitor)
{
foreach ($this->elements as $element) {
$element->accept($visitor);
}
}
}
$visitor = new ConcreteVisitor();
$elementA = new ConcreteElement();
$elementB = new ConcreteElement();
$objectStructure = new ObjectStructure();
$objectStructure->add($elementA);
$objectStructure->add($elementB);
$objectStructure->accept($visitor);
優點
- 增加新的訪問者無須修改原有系統。
- 相同的物件結構可以供多個不同的訪問者訪問。
- 將有關元素物件的訪問行為集中到一個訪問者物件中。
缺點
- 增加新的元素類要在訪問者中增加一個新的操作,並在每一個具體訪問者類中增加相應的具體操作。
- 具體元素對訪問者公佈細節,違反了迪米特原則。
何時使用
- 在訪問者中針對每一種具體的型別都提供了一個訪問操作,不同型別的物件可以有不同的訪問操作。
- 物件結構中物件對應的類很少改變,但經常需要在此物件結構上定義新的操作。
- 物件結構可以被多個不同的訪問者類所使用,將物件本身與物件的訪問操作分離。
實際應用場景
- 記者採訪。
- 醫院付藥費。計價員和藥房工作者作為訪問者,藥品作為訪問元素、處方單作為物件結構。
- 某公司人力資源部負責彙總每週員工工作時間,而財務部負責計算每週員工工資。
- 藝術公司用紙畫出圖畫。造幣公司用紙可以印出紙幣。
- 評定工程師一年的工作績效。CTO關注工程師的程式碼量,CEO關注的是工程師的KPI。
- 檔案遍歷。目錄和檔案是訪問者,檔案樹節點是訪問元素。
- 報表。不同部門對同樣的報表有不同的需求。
本作品採用《CC 協議》,轉載必須註明作者和本文連結