程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP綜合 >> 學習php設計模式 php實現訪問者模式(Visitor)

學習php設計模式 php實現訪問者模式(Visitor)

編輯:PHP綜合

訪問者模式表示一個作用於某對象結構中各元素的操作。它可以在不修改各元素類的前提下定義作用於這些元素的新操作,即動態的增加具體訪問者角色。
訪問者模式利用了雙重分派。先將訪問者傳入元素對象的Accept方法中,然後元素對象再將自己傳入訪問者,之後訪問者執行元素的相應方法。
訪問者模式多用在聚集類型多樣的情況下。在普通的形式下必須判斷每個元素是屬於什麼類型然後進行相應的操作,從而誕生出冗長的條件轉移語句。而訪問者模式則可以比較好的解決這個問題。對每個元素統一調用$element->accept($vistor)即可。
訪問者模式多用於被訪問的類結構比較穩定的情況下,即不會隨便添加子類。訪問者模式允許被訪問結構添加新的方法。
Visitor模式實際上是分離了對象結構中的元素和對這些元素進行操作的行為,從而使我們在根據對象結構中的元素進行方法調用的時候,不需要使用IF語句判斷,也就是封裝了操作。
但是,如果增加新的元素節點,則會導致包括訪問者接口及其子類的改變,這就會違反了面向對象中的開閉原則
當這種情況出現時,一般表示訪問者模式已經可能不再適用了,或者說設計時就有問題了!
一、Visitor模式結構圖

二、Visitor模式中主要角色

1)抽象訪問者角色(Visitor):為該對象結構(ObjectStructure)中的每一個具體元素提供一個訪問操作接口。該操作接口的名字和參數標識了 要訪問的具體元素角色。這樣訪問者就可以通過該元素角色的特定接口直接訪問它。
2)具體訪問者角色(ConcreteVisitor):實現抽象訪問者角色接口中針對各個具體元素角色聲明的操作。
3)抽象節點(Node)角色:該接口定義一個accept操作接受具體的訪問者。
4)具體節點(Node)角色:實現抽象節點角色中的accept操作。
5) 對象結構角色(ObjectStructure):這是使用訪問者模式必備的角色。它要具備以下特征:能枚舉它的元素;可以提供一個高層的接口以允許該訪問者訪問它的元素;可以是一個復合(組合模式)或是一個集合,如一個列表或一個無序集合(在PHP中我們使用數組代替,因為PHP中的數組本來就是一個可以放置任何類型數據的集合)
三、Visitor模式的優缺點
訪問者模式有如下的優點
1)訪問者模式使得增加新的操作變得很容易。使用訪問者模式可以在不用修改具體元素類的情況下增加新的操作。它主要是通過元素類的accept方法來接受一個新的visitor對象來實現的。如果一些操作依賴於一個復雜的結構對象的話,那麼一般而言,增加新的操作會很復雜。而使用訪問者模式,增加新的操作就意味著增加一個新的訪問者類,因此,變得很容易。
2)訪問者模式將有關的行為集中到一個訪問者對象中,而不是分散到一個個的節點類中。
3)訪問者模式可以跨過幾個類的等級結構訪問屬於不同的等級結構的成員類。迭代子只能訪問屬於同一個類型等級結構的成員對象,而不能訪問屬於不同等級結構的對象。訪問者模式可以做到這一點。
4)積累狀態。每一個單獨的訪問者對象都集中了相關的行為,從而也就可以在訪問的過程中將執行操作的狀態積累在自己內部,而不是分散到很多的節點對象中。這是有益於系統維護的優點。

訪問者模式有如下的缺點
1)增加新的節點類變得很困難。每增加一個新的節點都意味著要在抽象訪問者角色中增加一個新的抽象操作,並在每一個具體訪問者類中增加相應的具體操作。
2)破壞封裝。訪問者模式要求訪問者對象訪問並調用每一個節點對象的操作,這隱含了一個對所有節點對象的要求:它們必須暴露一些自己的操作和內部狀態。不然,訪問者的訪問就變得沒有意義。由於訪問者對象自己會積累訪問操作所需的狀態,從而使這些狀態不再存儲在節點對象中,這也是破壞封裝的。

使用Visitor模式的前提: 對象群結構中(Collection) 中的對象類型很少改變。
在接口Visitor和Element中,確保Element很少變化,也就是說,確保不能頻繁的添加新的Element元素類型加進來,可以變化的是訪問者行為或操作,也就是Visitor的不同子類可以有多種,這樣使用訪問者模式最方便.
如果對象集合中的對象集合經常有變化, 那麼不但Visitor實現要變化,ConcreteVisitor也要增加相應行為,GOF建議是,不如在這些對象類中直接逐個定義操作,無需使用訪問者設計模式。

四、Visitor模式與其它模式

1、如果所浏覽的結構對象是線性的,使用迭代模式而不是訪問者模式也是可以的
2、訪問者模式浏覽合成模式的一些結構對象
以上兩點來自《Java與模式》一書

五、Visitor模式PHP示例

<?php
 
interface Visitor {
 public function visitConcreteElementA(ConcreteElementA $elementA);
 public function visitConcreteElementB(concreteElementB $elementB);
}
 
interface Element {
 public function accept(Visitor $visitor);
}
 
/**
 * 具體的訪問者1
 */
class ConcreteVisitor1 implements Visitor {
 public function visitConcreteElementA(ConcreteElementA $elementA) {
 echo $elementA->getName() . " visitd by ConcerteVisitor1 <br />";
 }
 
 public function visitConcreteElementB(ConcreteElementB $elementB) {
 echo $elementB->getName() . " visited by ConcerteVisitor1 <br />";
 }
 
}
 
/**
 * 具體的訪問者2
 */
class ConcreteVisitor2 implements Visitor {
 public function visitConcreteElementA(ConcreteElementA $elementA) {
 echo $elementA->getName() . " visitd by ConcerteVisitor2 <br />";
 }
 
 public function visitConcreteElementB(ConcreteElementB $elementB) {
 echo $elementB->getName() . " visited by ConcerteVisitor2 <br />";
 }
 
}
 
/**
 * 具體元素A
 */
class ConcreteElementA implements Element {
 private $_name;
 
 public function __construct($name) {
 $this->_name = $name;
 }
 
 public function getName() {
 return $this->_name;
 }
 
 /**
 * 接受訪問者調用它針對該元素的新方法
 * @param Visitor $visitor
 */
 public function accept(Visitor $visitor) {
 $visitor->visitConcreteElementA($this);
 }
 
}
 
/**
 * 具體元素B
 */
class ConcreteElementB implements Element {
 private $_name;
 
 public function __construct($name) {
 $this->_name = $name;
 }
 
 public function getName() {
 return $this->_name;
 }
 
 /**
 * 接受訪問者調用它針對該元素的新方法
 * @param Visitor $visitor
 */
 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);
 }
 }
}
 
class Client {
 
 /**
 * Main program.
 */
 public static function main() {
 $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);
 }
 
}
 
Client::main();
?>

以上就是使用php實現訪問者模式的代碼,還有一些關於訪問者模式的概念區分,希望對大家的學習有所幫助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved