訪問者,就像我們去別人家訪問,或者別人來我們家看望我們一樣,我們每個人都像是一個物體,而來訪的人都會一一的和我們打招呼,畢竟,我們中華民族是非常講究禮數和好客的民族,訪問者是GoF23個設計模式中最復雜的一個模式,也是各類設計模式教材都放在最后的一個模式,先不管難度如何,我們先看看它的定義和實作,
Gof類圖及解釋
GoF定義:表示一個作用于某物件結構中的各元素的操作,它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作
GoF類圖

代碼實作
interface Visitor
{
public function VisitConcreteElementA(ConcreteElementA $a);
function VisitConcreteElementB(ConcreteElementB $b);
}
class ConcreteVisitor1 implements Visitor
{
public function VisitConcreteElementA(ConcreteElementA $a)
{
echo get_class($a) . "被" . get_class($this) . "訪問", PHP_EOL;
}
public function VisitConcreteElementB(ConcreteElementB $b)
{
echo get_class($b) . "被" . get_class($this) . "訪問", PHP_EOL;
}
}
class ConcreteVisitor2 implements Visitor
{
public function VisitConcreteElementA(ConcreteElementA $a)
{
echo get_class($a) . "被" . get_class($this) . "訪問", PHP_EOL;
}
public function VisitConcreteElementB(ConcreteElementB $b)
{
echo get_class($b) . "被" . get_class($this) . "訪問", PHP_EOL;
}
}
抽象的訪問者介面及兩個具體實作,可以看作是一家小兩口來我們家作客咯!
interface Element
{
public function Accept(Visitor $v);
}
class ConcreteElementA implements Element
{
public function Accept(Visitor $v)
{
$v->VisitConcreteElementA($this);
}
public function OperationA()
{
}
}
class ConcreteElementB implements Element
{
public function Accept(Visitor $v)
{
$v->VisitConcreteElementB($this);
}
public function OperationB()
{
}
}
元素抽象及實作,也可以看作是要訪問的物體,當然就是我和我媳婦啦,
class ObjectStructure
{
private $elements = [];
public function Attach(Element $element)
{
$this->elements[] = $element;
}
public function Detach(Element $element)
{
$position = 0;
foreach ($this->elements as $e) {
if ($e == $element) {
unset($this->elements[$position]);
break;
}
$position++;
}
}
public function Accept(Visitor $visitor)
{
foreach ($this->elements as $e) {
$e->Accept($visitor);
}
}
}
這是一個物件結構,用于保存元素物體并進行訪問呼叫,大家在客廳里見面,互相寒暄嘛,這里就是個客廳
$o = new ObjectStructure();
$o->Attach(new ConcreteElementA());
$o->Attach(new ConcreteElementB());
$v1 = new ConcreteVisitor1();
$v2 = new ConcreteVisitor2();
$o->Accept($v1);
$o->Accept($v2);
客戶端的呼叫,總算讓大家正式見面了,互相介紹握手,一次訪問就愉快的完成了,
- 讓訪問者呼叫指定的元素,這里需要注意的,訪問者呼叫元素的行為一般是固定的,很少會改變的,也就是VisitConcreteElementA()、VisitConcreteElementB()這兩個方法,也就是定義物件結構的類很少改變,但經常需要在此結構上定義新的操作時,會使用訪問者模式
- 需要對一個物件結構中的物件進行很多不同的并且不相關的操作,而你想避免讓這些操作“污染”這些物件的類時,適用于訪問者模式
- 訪問者模式適合資料結構不變化的情況,所以,它是一種平常你用不上,但一旦需要的時候就只能用這種模式的模式,GoF:“大多時候你并不需要訪問者模式,但當一旦你需要訪問者模式時,那就是真的需要它了”,因為很少有資料結構不發生變化的情況
- 訪問者模式的一些優缺點:易于增加新的操作;集中相關的操作而分離無關的操作;增加新的ConcreteElement類很困難;通過類層次進行訪問;累積狀態;破壞封裝
我們公司的賬務,只有收入和支出兩項(Element),但是不同的部門(Visitor)訪問的時候會給出不同的內容,比如我查看的時候只需要查看每月或每季度的匯總資料即可,財務總監則需要詳細的收支記錄,而會計在做賬時更是需要完整的明細,可見,公司的運營還真的是需要非常廣泛的知識的,不僅是管理能力,賬務知識也是必要了解的內容!!
完整代碼:https://github.com/zhangyue0503/designpatterns-php/blob/master/23.visitor/source/visitor.php
實體
最后一個模式的例子還是回到我們的資訊發送上來,同樣的還是多個服務商,它們作為訪問者需要去使用各自的短信發送及APP推送介面,這時,就可以使用訪問者模式來進行操作,實作這些訪問者的全部操作,
訪問者模式資訊發送

完整原始碼:https://github.com/zhangyue0503/designpatterns-php/blob/master/23.visitor/source/visitor-msg.php
<?php
interface ServiceVisitor
{
public function SendMsg(SendMessage $s);
function PushMsg(PushMessage $p);
}
class AliYun implements ServiceVisitor
{
public function SendMsg(SendMessage $s)
{
echo '阿里云發送短信!', PHP_EOL;
}
public function PushMsg(PushMessage $p)
{
echo '阿里云推送資訊!', PHP_EOL;
}
}
class JiGuang implements ServiceVisitor
{
public function SendMsg(SendMessage $s)
{
echo '極光發送短信!', PHP_EOL;
}
public function PushMsg(PushMessage $p)
{
echo '極光推送短信!', PHP_EOL;
}
}
interface Message
{
public function Msg(ServiceVisitor $v);
}
class PushMessage implements Message
{
public function Msg(ServiceVisitor $v)
{
echo '推送腳本啟動:';
$v->PushMsg($this);
}
}
class SendMessage implements Message
{
public function Msg(ServiceVisitor $v)
{
echo '短信腳本啟動:';
$v->SendMsg($this);
}
}
class ObjectStructure
{
private $elements = [];
public function Attach(Message $element)
{
$this->elements[] = $element;
}
public function Detach(Message $element)
{
$position = 0;
foreach ($this->elements as $e) {
if ($e == $element) {
unset($this->elements[$position]);
break;
}
$position++;
}
}
public function Accept(ServiceVisitor $visitor)
{
foreach ($this->elements as $e) {
$e->Msg($visitor);
}
}
}
$o = new ObjectStructure();
$o->Attach(new PushMessage());
$o->Attach(new SendMessage());
$v1 = new AliYun();
$v2 = new JiGuang();
$o->Accept($v1);
$o->Accept($v2);
說明
- 我們假定發送短信和發送推送是不變的兩個行為,也就是它們倆的資料結構是穩定不變的
- 這樣我們就可以方便的增加ServiceVisitor,當增加百度云或者別的什么短信提供商時,就很方便的增加訪問者就可以了
- 訪問者模式比較適合資料結構穩定的結構,比如帳單只有收入支出、人的性別只有男女等
下期看點
至此,設計模式部分我們已經全部學習完了,其實還少了一個解釋器模式,但這個模式確實是真的的非常少見,有興趣的朋友可以自行去了解哈,
關注公眾號:【硬核專案經理】獲取最新文章
添加微信/QQ好友:【xiaoyuezigonggong/149844827】免費得PHP、專案管理學習資料
知乎、公眾號、抖音、頭條搜索【硬核專案經理】
B站ID:482780532
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/246431.html
標籤:其他
