訪問者,就像咱們去別人家訪問,或者別人來咱們家看望咱們同樣。咱們每一個人都像是一個實體,而來訪的人都會一一的和咱們打招呼。畢竟,咱們中華民族是很是講究禮數和好客的民族。訪問者是GoF23個設計模式中最複雜的一個模式,也是各種設計模式教材都放在最後的一個模式。先無論難度如何,咱們先看看它的定義和實現。php
GoF定義:表示一個做用於某對象結構中的各元素的操做。它使你能夠在不改變各元素的類的前提下定義做用於這些元素的新操做git
GoF類圖github
代碼實現設計模式
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);
}
}
}
複製代碼
這是一個對象結構,用於保存元素實體並進行訪問調用。你們在客廳裏見面,互相寒暄嘛,這裏就是個客廳this
$o = new ObjectStructure();
$o->Attach(new ConcreteElementA());
$o->Attach(new ConcreteElementB());
$v1 = new ConcreteVisitor1();
$v2 = new ConcreteVisitor2();
$o->Accept($v1);
$o->Accept($v2);
複製代碼
客戶端的調用,總算讓你們正式見面了,互相介紹握手。一次訪問就愉快的完成了。阿里雲
咱們公司的帳務,只有收入和支出兩項(Element),可是不一樣的部門(Visitor)訪問的時候會給出不一樣的內容。好比我查看的時候只須要查看每個月或每季度的彙總數據便可,財務總監則須要詳細的收支記錄,而會計在作帳時更是須要完整的明細。可見,公司的運營還真的是須要很是普遍的知識的,不只是管理能力,帳務知識也是必要了解的內容!!spa
完整代碼:github.com/zhangyue050…設計
最後一個模式的例子仍是回到咱們的信息發送上來。一樣的仍是多個服務商,它們做爲訪問者須要去使用各自的短信發送及APP推送接口。這時,就可使用訪問者模式來進行操做,實現這些訪問者的所有操做。
訪問者模式信息發送
<?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);
複製代碼
說明
至此,設計模式部分咱們已經所有學習完了。其實還少了一個解釋器模式,但這個模式確實是真的的很是少見,有興趣的朋友能夠自行去了解哈。