訪問者模式是一種行爲型模式,訪問者表示一個做用於某對象結構中各元素的操做。它能夠在不修改各元素類的前提下定義做用於這些元素的新操做,即動態的增長具體訪問者角色。php
訪問者模式利用了雙重分派。先將訪問者傳入元素對象的Accept方法中,而後元素對象再將本身傳入訪問者,以後訪問者執行元素的相應方法。數組
主要角色this
抽象訪問者角色(Visitor):爲該對象結構(ObjectStructure)中的每個具體元素提供一個訪問操做接口。該操做接口的名字和參數標識了 要訪問的具體元素角色。這樣訪問者就能夠經過該元素角色的特定接口直接訪問它。
具體訪問者角色(ConcreteVisitor):實現抽象訪問者角色接口中針對各個具體元素角色聲明的操做。
抽象節點(Node)角色:該接口定義一個accept操做接受具體的訪問者。
具體節點(Node)角色:實現抽象節點角色中的accept操做。
對象結構角色(ObjectStructure):這是使用訪問者模式必備的角色。它要具有如下特徵:能枚舉它的元素;能夠提供一個高層的接口以容許該訪問者訪問它的元素;能夠是一個複合(組合模式)或是一個集合,如一個列表或一個無序集合(在PHP中咱們使用數組代替,由於PHP中的數組原本就是一個能夠放置任何類型數據的集合)
適用性對象
訪問者模式多用在彙集類型多樣的狀況下。在普通的形式下必須判斷每一個元素是屬於什麼類型而後進行相應的操做,從而誕生出冗長的條件轉移語句。而訪問者模式則能夠比較好的解決這個問題。對每一個元素統一調用element−>accept(vistor)便可。
訪問者模式多用於被訪問的類結構比較穩定的狀況下,即不會隨便添加子類。訪問者模式容許被訪問結構添加新的方法。blog
<?php interface Visitor { // 抽象訪問者角色 public function visitConcreteElementA(ConcreteElementA $elementA); public function visitConcreteElementB(concreteElementB $elementB); } interface Element { // 抽象節點角色 public function accept(Visitor $visitor); } class ConcreteVisitor1 implements Visitor { // 具體的訪問者1 public function visitConcreteElementA(ConcreteElementA $elementA) {} public function visitConcreteElementB(ConcreteElementB $elementB) {} } class ConcreteVisitor2 implements Visitor { // 具體的訪問者2 public function visitConcreteElementA(ConcreteElementA $elementA) {} public function visitConcreteElementB(ConcreteElementB $elementB) {} } class ConcreteElementA implements Element { // 具體元素A private $_name; public function __construct($name) { $this->_name = $name; } public function getName() { return $this->_name; } public function accept(Visitor $visitor) { // 接受訪問者調用它針對該元素的新方法 $visitor->visitConcreteElementA($this); } } class ConcreteElementB implements Element { // 具體元素B private $_name; public function __construct($name) { $this->_name = $name;} public function getName() { return $this->_name; } public function accept(Visitor $visitor) { // 接受訪問者調用它針對該元素的新方法 $visitor->visitConcreteElementB($this); } } class ObjectStructure { // 對象結構 即元素的集合 private $_collection; public function __construct() { $this->_collection = array(); } public function attach(Element $element) { return array_push($this->_collection, $element); } public function detach(Element $element) { $index = array_search($element, $this->_collection); if ($index !== FALSE) { unset($this->_collection[$index]); } return $index; } public function accept(Visitor $visitor) { foreach ($this->_collection as $element) { $element->accept($visitor); } } } // client $elementA = new ConcreteElementA("ElementA"); $elementB = new ConcreteElementB("ElementB"); $elementA2 = new ConcreteElementB("ElementA2"); $visitor1 = new ConcreteVisitor1(); $visitor2 = new ConcreteVisitor2(); $os = new ObjectStructure(); $os->attach($elementA); $os->attach($elementB); $os->attach($elementA2); $os->detach($elementA); $os->accept($visitor1); $os->accept($visitor2);