访问者模式是一种行为型模式,访问者表示一个做用于某对象结构中各元素的操做。它能够在不修改各元素类的前提下定义做用于这些元素的新操做,即动态的增长具体访问者角色。php
访问者模式利用了双重分派。先将访问者传入元素对象的Accept方法中,而后元素对象再将本身传入访问者,以后访问者执行元素的相应方法。数组
主要角色this
抽象访问者角色(Visitor):为该对象结构(ObjectStructure)中的每个具体元素提供一个访问操做接口。该操做接口的名字和参数标识了 要访问的具体元素角色。这样访问者就能够经过该元素角色的特定接口直接访问它。
具体访问者角色(ConcreteVisitor):实现抽象访问者角色接口中针对各个具体元素角色声明的操做。
抽象节点(Node)角色:该接口定义一个accept操做接受具体的访问者。
具体节点(Node)角色:实现抽象节点角色中的accept操做。
对象结构角色(ObjectStructure):这是使用访问者模式必备的角色。它要具有如下特征:能枚举它的元素;能够提供一个高层的接口以容许该访问者访问它的元素;能够是一个复合(组合模式)或是一个集合,如一个列表或一个无序集合(在PHP中咱们使用数组代替,由于PHP中的数组原本就是一个能够放置任何类型数据的集合)
适用性对象
访问者模式多用在汇集类型多样的状况下。在普通的形式下必须判断每一个元素是属于什么类型而后进行相应的操做,从而诞生出冗长的条件转移语句。而访问者模式则能够比较好的解决这个问题。对每一个元素统一调用element−>accept(vistor)便可。
访问者模式多用于被访问的类结构比较稳定的状况下,即不会随便添加子类。访问者模式容许被访问结构添加新的方法。blog
<?php interface Visitor { // 抽象访问者角色 public function visitConcreteElementA(ConcreteElementA $elementA); public function visitConcreteElementB(concreteElementB $elementB); } interface Element { // 抽象节点角色 public function accept(Visitor $visitor); } class ConcreteVisitor1 implements Visitor { // 具体的访问者1 public function visitConcreteElementA(ConcreteElementA $elementA) {} public function visitConcreteElementB(ConcreteElementB $elementB) {} } class ConcreteVisitor2 implements Visitor { // 具体的访问者2 public function visitConcreteElementA(ConcreteElementA $elementA) {} public function visitConcreteElementB(ConcreteElementB $elementB) {} } class ConcreteElementA implements Element { // 具体元素A private $_name; public function __construct($name) { $this->_name = $name; } public function getName() { return $this->_name; } public function accept(Visitor $visitor) { // 接受访问者调用它针对该元素的新方法 $visitor->visitConcreteElementA($this); } } class ConcreteElementB implements Element { // 具体元素B private $_name; public function __construct($name) { $this->_name = $name;} public function getName() { return $this->_name; } public function accept(Visitor $visitor) { // 接受访问者调用它针对该元素的新方法 $visitor->visitConcreteElementB($this); } } class ObjectStructure { // 对象结构 即元素的集合 private $_collection; public function __construct() { $this->_collection = array(); } public function attach(Element $element) { return array_push($this->_collection, $element); } public function detach(Element $element) { $index = array_search($element, $this->_collection); if ($index !== FALSE) { unset($this->_collection[$index]); } return $index; } public function accept(Visitor $visitor) { foreach ($this->_collection as $element) { $element->accept($visitor); } } } // client $elementA = new ConcreteElementA("ElementA"); $elementB = new ConcreteElementB("ElementB"); $elementA2 = new ConcreteElementB("ElementA2"); $visitor1 = new ConcreteVisitor1(); $visitor2 = new ConcreteVisitor2(); $os = new ObjectStructure(); $os->attach($elementA); $os->attach($elementB); $os->attach($elementA2); $os->detach($elementA); $os->accept($visitor1); $os->accept($visitor2);