[toc]
## 舉個例子
> 有一千個讀者, 就有一千個哈姆雷特
> 同樣是設計模式的文章
> 技術圈評價:能抓住模式的核心思想、深入淺出,很有見地!
> 做產品和設計的評價:文章很有層次感!
> IT 圈外評價:嗯, 文章很長, 嗯, 好厲害...
## 代碼示例
```php
<?php
// 《俗話說PHP設計模式》一書
class DesignPatternBook {
public function getName() {
return "《俗話說PHP設計模式》";
}
}
// 訪問者,也就是讀者
abstract class Reader {
public function read($book) {
}
}
class Engineer extends Reader {
public function read($book) {
echo "技術狗讀" . $book->getName() . "一書后的感受:能抓住模式的核心思想,深入淺出,很有見地!" . PHP_EOL;
}
}
// 產品經理
class ProductManager extends Reader {
public function read($book) {
echo "產品經理讀" . $book->getName() . "一書后的感受:文章很有層次感!" . PHP_EOL;
}
}
// IT圈外的朋友
class OtherFriend extends Reader {
public function read($book) {
echo "IT圈外的朋友讀" . $book->getName() . "一書后的感受:嗯, 文章很長, 嗯, 好厲害..." . PHP_EOL;
}
}
// 測試代碼
$book = new DesignPatternBook();
$fans = [new Engineer(), new ProductManager(), new OtherFriend()];
foreach ($fans as $fan) {
$fan->read($book);
}
```
```
D:\soft\php72\php.exe D:\project\php_dp\index.php
技術狗讀《俗話說PHP設計模式》一書后的感受:能抓住模式的核心思想,深入淺出,很有見地!
產品經理讀《俗話說PHP設計模式》一書后的感受:文章很有層次感!
IT圈外的朋友讀《俗話說PHP設計模式》一書后的感受:嗯, 文章很長, 嗯, 好厲害...
Process finished with exit code 0
```
## 代碼說明
1. 在上面的示例中,同樣內容的一本書,不同類型的讀者看到了不同的內容,讀到了不同的味道。
2. 這里讀者和書是兩類事物,他們雖有聯系,卻是比較弱的聯系,因此我我們將其分開處理,
3. 這種方式在程序中叫訪問者模式,也可簡稱為訪問模式。這里的讀者就是訪問者,書就是被訪問的對象,閱讀是訪問的行為。
## 什么是訪問模式?
> 封裝一些作用于某種數據結構中各元素的操作,它可以在不改變數據結構的前提下定義作用于這些元素的新的操作。
> 訪問模式的核心思想在于:可以在不改變數據結構的前提下定義作用于這些元素的新操作。
> 將數據結構和操作(或算法)進行解耦,而且能更方便地拓展新的操作。

## 設計要點
1. **訪問者(Visitor)**: 負責對數據結點進行訪問和操作。
1. **數據結點(DataNode)**: 即要被操作的數據對象。
1. **對象結構(ObjectStructure)**: 數據結構的管理類,也是數據對象的一個容器,可遍歷容器內的所有元素。
## 優缺點
**訪問模式的優點**
1. 將數據和操作(算法)分離、降低了耦合度。將有關元素對象的訪問行為集中到一個訪問者對象中,而不是分散在一個個的元素類中,類的職責更加清晰。
2. 增加新的訪問操作很方便。使用訪問者模式,增加新的訪問操作就意味著增加一個新的具體訪問者類,實現簡單,無須修改源代碼
3. 讓用戶能夠在不修改現有元素類層次結構的情況下,定義作用于該層次結構的操作。
**訪問模式的缺點**
1. 增加新的元素類很困難。在訪問者模式中,每增加一個新的元素類都意味著要在抽象訪問者角色中增加一個新的抽象操作,并在每一個具體訪問者類中增加相應的具體操作
1. 破壞數據對象的封裝性。訪問者模式要求訪問者對象訪問并調用每一個元素對象的操作,這意味著元素對象有時候必須暴露一些自己的內部操作和內部狀態,否則無法供訪問者訪問。
## 應用場景
1. 對象結構中包含的對象類比較少,而且這些類需要比較固定,很少改變,但經常需要在此對象結構上定義新的操作。
1. 一個對象結構包含多個類型的對象,希望對這些對象實施一些依賴其具體類型的操作。
2. 在訪問者中針對每一種具體的類型都提供了一個訪問操作,不同類型的對象可以有不同的訪問操作。
1. 需要對一個對象結構中的對象進行很多不同的并且不相關的操作,而需要避免讓這些操作“污染”這些對象的類,也不希望在增加新操作時修改這些類。
2. 訪問者模式使得我們可以將相關的訪問操作集中起來定義在訪問者類中,對象結構可以被多個不同的訪問者類所使用,將對象本身與對象的訪問操作分離。