訪問者模式表示一個作用於某對象結構中的各元素的操作。它使你可以在不改變各元素類的前提下定義作用於這些元素的新操作。
UML類圖:
角色:
1.抽象訪問者(State):爲該對象結構中具體元素角色聲明一個訪問操作接口。該操作接口的名字和參數標識了發送訪問請求給具體訪問者的具體元素角色,這樣訪問者就可以通過該元素角色的特定接口直接訪問它。
2.具體訪問者(Success):實現訪問者聲明的接口。
3.抽象元素(Person):定義一個接受訪問操作accept(),它以一個訪問者作爲參數。
4. 具體元素(Man):實現了抽象元素所定義的接受操作接口。
5.結構對象(ObjectStruct):這是使用訪問者模式必備的角色。它具備以下特性:能枚舉它的元素;可以提供一個高層接口以允許訪問者訪問它的元素;如有需要,可以設計成一個複合對象或者一個聚集(如一個列表或無序集合)。
核心代碼:
<span style="color:#000000;"><?php
/**
* Created by PhpStorm.
* User:Jang
* Date:2015/6/11
* Tim: 9 :40
*/
/*男人這本書的內容要比封面吸引人;女人這本書的封面通常比內容更吸引人
男人成功時,背後多半有一個偉大的女人;女人成功時,背後多半有一個失敗的男人
男人失敗時,悶頭喝酒,誰也不用勸;女人失敗時,眼淚汪汪,誰也勸不了
男人戀愛時,凡事不懂也要裝懂;女人戀愛時,遇事懂也要裝作不懂*/
//抽象狀態
abstract class State
{
protected $state_name;
//得到男人反應
public abstract function GetManAction(VMan $elementM);
//得到女人反應
public abstract function GetWomanAction(VWoman $elementW);
}
//抽象人
abstract class Person
{
public $type_name;
public abstract function Accept(State $visitor);
}
//成功狀態
class Success extends State
{
public function __construct()
{
$this->state_name="成功";
}
public function GetManAction(VMan $elementM)
{
echo "{$elementM->type_name}:{$this->state_name}時,背後多半有一個偉大的女人。<br/>";
}
public function GetWomanAction(VWoman $elementW)
{
echo "{$elementW->type_name} :{$this->state_name}時,背後大多有一個不成功的男人。<br/>";
}
}
//失敗狀態
class Failure extends State
{
public function __construct()
{
$this->state_name="失敗";
}
public function GetManAction(VMan $elementM)
{
echo "{$elementM->type_name}:{$this->state_name}時,悶頭喝酒,誰也不用勸。<br/>";
}
public function GetWomanAction(VWoman $elementW)
{
echo "{$elementW->type_name} :{$this->state_name}時,眼淚汪汪,誰也勸不了。<br/>";
}
}
//戀愛狀態
class Amativeness extends State
{
public function __construct()
{
$this->state_name="戀愛";
}
public function GetManAction(VMan $elementM)
{
echo "{$elementM->type_name}:{$this->state_name}時,凡事不懂也要裝懂。<br/>";
}
public function GetWomanAction(VWoman $elementW)
{
echo "{$elementW->type_name} :{$this->state_name}時,遇事懂也要裝作不懂。<br/>";
}
}
//男人
class VMan extends Person
{
function __construct()
{
$this->type_name="男人";
}
public function Accept(State $visitor)
{
$visitor->GetManAction($this);
}
}
//女人
class VWoman extends Person
{
public function __construct()
{
$this->type_name="女人";
}
public function Accept(State $visitor)
{
$visitor->GetWomanAction($this);
}
}
//對象結構
class ObjectStruct
{
private $elements=array();
//增加
public function Add(Person $element)
{
array_push($this->elements,$element);
}
//移除
public function Remove(Person $element)
{
foreach($this->elements as $k=>$v)
{
if($v==$element)
{
unset($this->elements[$k]);
}
}
}
//查看顯示
public function Display(State $visitor)
{
foreach ($this->elements as $v)
{
$v->Accept($visitor);
}
}
}</span>
測試客戶端代碼:
header("Content-Type:text/html;charset=utf-8");
//------------------------訪問者模式--------------------
require_once "./Visitor/Visitor.php";
$os = new ObjectStruct();
$os->Add(new VMan());
$os->Add(new VWoman());
//成功時反應
$ss = new Success();
$os->Display($ss);
//失敗時反應
$fs = new Failure();
$os->Display($fs);
//戀愛時反應
$ats=new Amativeness();
$os->Display($ats);
適用場景及優勢:
1) 一個對象結構包含很多類對象,它們有不同的接口,而你想對這些對象實施一些依賴於其具體類的操作。
2) 需要對一個對象結構中的對象進行很多不同的並且不相關的操作,而你想避免讓這些操作“污染”這些對象的類。Visitor模式使得你可以將相關的操作集中起來定義在一個類中。
3) 當該對象結構被很多應用共享時,用Visitor模式讓每個應用僅包含需要用到的操作。
4) 定義對象結構的類很少改變,但經常需要在此結構上定義新的操作。改變對象結構類需要重定義對所有訪問者的接口,這可能需要很大的代價。如果對象結構類經常改變,那麼可能還是在這些類中定義這些操作較好。