簡介: 訪問者模式,屬於行為型的設計模式。表示一個作用於某對象結構中的各元素的操作。它是你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。 適用場景: 類中有易於變化的演算法。 希望數據結構與數據分離。 優點: 便於增加新的操作,相當於增加一個訪問者。訪問者模式將有關行為集中到一個訪問者對象 ...
簡介:
訪問者模式,屬於行為型的設計模式。表示一個作用於某對象結構中的各元素的操作。它是你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。
適用場景:
- 類中有易於變化的演算法。
- 希望數據結構與數據分離。
優點:
- 便於增加新的操作,相當於增加一個訪問者。訪問者模式將有關行為集中到一個訪問者對象中。
缺點:
元素變更比較困難,如為被訪問的對象增加、減少一些屬性,相應的訪問者也需要進行修改 ;
代碼:
/**
*Component介面聲明瞭一個“accept”方法,該方法應將base訪問者介面作為參數。
*/
interface Component
{
public function accept(Visitor $visitor): void;
}
/**
*每個具體組件必須以這樣的方式實現“accept”方法:它調用與組件類對應的訪問者方法。
*/
class ConcreteComponentA implements Component
{
/*
* 註意,我們調用的是與當前類名匹配的“visitContainerComponentA”。通過這種方式,我們讓訪問者知道它所使用的組件的類
*/
public function accept(Visitor $visitor): void
{
$visitor->visitConcreteComponentA($this);
}
/*
* 具體組件可能具有其基類或介面中不存在的特殊方法。Visitor仍然能夠使用這些方法,因為它知道組件的具體類
*/
public function exclusiveMethodOfConcreteComponentA(): string
{
return "A";
}
}
class ConcreteComponentB implements Component
{
/**
* 此處相同:visitContainerComponentB=>ConcreteComponentB
*/
public function accept(Visitor $visitor): void
{
$visitor->visitConcreteComponentB($this);
}
public function specialMethodOfConcreteComponentB(): string
{
return "B";
}
}
/**
*Visitor介面聲明瞭一組與組件類相對應的訪問方法。訪問方法的簽名允許訪問者標識它正在處理的組件的確切類。
*/
interface Visitor
{
public function visitConcreteComponentA(ConcreteComponentA $element): void;
public function visitConcreteComponentB(ConcreteComponentB $element): void;
}
/**
*Concrete Visitors實現了同一演算法的多個版本,它可以與所有具體組件類一起工作。當將Visitor模式與複雜的對象結構(如Composite樹)一起使用時,您可以體驗到它的最大好處。在這種情況下,在對結構的各個對象執行訪問者的方法時,存儲演算法的一些中間狀態可能會有所幫助。
*/
class ConcreteVisitor1 implements Visitor
{
public function visitConcreteComponentA(ConcreteComponentA $element): void
{
echo $element->exclusiveMethodOfConcreteComponentA() . " + ConcreteVisitor1\n";
}
public function visitConcreteComponentB(ConcreteComponentB $element): void
{
echo $element->specialMethodOfConcreteComponentB() . " + ConcreteVisitor1\n";
}
}
class ConcreteVisitor2 implements Visitor
{
public function visitConcreteComponentA(ConcreteComponentA $element): void
{
echo $element->exclusiveMethodOfConcreteComponentA() . " + ConcreteVisitor2\n";
}
public function visitConcreteComponentB(ConcreteComponentB $element): void
{
echo $element->specialMethodOfConcreteComponentB() . " + ConcreteVisitor2\n";
}
}
/**
*客戶端代碼可以在任何一組元素上運行訪問者操作,而無需弄清楚它們的具體類。accept操作將調用指向訪問者對象中的適當操作。
*/
function clientCode(array $components, Visitor $visitor)
{
// ...
foreach ($components as $component) {
$component->accept($visitor);
}
// ...
}
//調用端
$components = [
new ConcreteComponentA(),
new ConcreteComponentB(),
];
echo "客戶端代碼通過基本訪問者界面與所有訪問者一起工作:\n";
$visitor1 = new ConcreteVisitor1();
clientCode($components, $visitor1);
echo "\n";
echo "它允許相同的客戶端代碼與不同類型的訪問者一起工作:\n";
$visitor2 = new ConcreteVisitor2();
clientCode($components, $visitor2);