访问者模式
我们去银行柜台办业务,一般情况下会开几个个人业务柜台的,你去其中任何一个柜台办理都是可以的。
我们的访问者模式可以很好付诸在这个场景中:对于银行柜台来说,他们是不用变化的,就是说今天和明天提供个人业务的柜台是不需要有变化的。
而我们作为访问者,今天来银行可能是取消费流水,明天来银行可能是去办理手机银行业务,这些是我们访问者的操作,一直是在变化的。 访问者模式主要将数据结构与数据操作分离。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操,即动态的添加访问者角色。 访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。 访问者模式利用了双重分派。先将访问者传入元素对象的Accept方法中,然后元素对象再将自己传入访问者,之后访问者执行元素的相应方法。 访问者模式使得增加新的操作变得很容易。使用访问者模式可以在不用修改具体元素类的情况下增加新的操作。它主要是通过元素类的accept方法来接受一个新的visitor对象来实现的。
如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,增加新的操作会很复杂。而使用访问者模式,增加新的操作就意味着增加一个新的访问者类,因此,变得很容易。
积累状态。每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中将执行操作的状态积累在自己内部,而不是分散到很多的节点对象中。这是有益于系统维护的优点
1 <?php 2 3 /** 4 * 和观察者模式有一丝相似 5 */ 6 7 /** 8 * 抽象访问者角色, 要定义好针对所有元素的处理操作 9 */ 10 interface Visitor { 11 public function visitConcreteElementA(ConcreteElementA $elementA); 12 public function visitConcreteElementB(concreteElementB $elementB); 13 } 14 15 /** 16 * 抽象元素角色 17 */ 18 interface Element { 19 public function accept(Visitor $visitor); 20 } 21 22 23 24 25 26 /** 27 * 具体的访问者1 28 */ 29 class ConcreteVisitor1 implements Visitor { 30 private $_name; 31 32 public function __construct($name) 33 { 34 $this->_name = $name; 35 } 36 37 public function visitConcreteElementA(ConcreteElementA $elementA) 38 { 39 echo "<br/>", "哈哈, 小妞({$elementA->getName()}), 给本大爷({$this->_name})笑一个"; 40 } 41 42 public function visitConcreteElementB(ConcreteElementB $elementB) 43 { 44 echo "<br/>", "哈哈, 小妞({$elementB->getName()}), 给本大爷({$this->_name})笑一个"; 45 } 46 } 47 48 /** 49 * 具体的访问者2 50 */ 51 class ConcreteVisitor2 implements Visitor { 52 private $_name; 53 54 public function __construct($name) 55 { 56 $this->_name = $name; 57 } 58 59 public function visitConcreteElementA(ConcreteElementA $elementA) 60 { 61 echo "<br/>", "哈哈, 小妞({$elementA->getName()}), 给本大爷({$this->_name})笑一个"; 62 } 63 64 public function visitConcreteElementB(ConcreteElementB $elementB) 65 { 66 echo "<br/>", "哈哈, 小妞({$elementB->getName()}), 给本大爷({$this->_name})笑一个"; 67 } 68 } 69 70 71 72 73 74 /** 75 * 具体元素A 76 */ 77 class ConcreteElementA implements Element { 78 private $_name; 79 80 public function __construct($name) 81 { 82 $this->_name = $name; 83 } 84 85 public function getName() 86 { 87 return $this->_name; 88 } 89 90 /** 91 * @param Visitor $visitor 接受访问者调用它针对该元素的新方法 92 */ 93 public function accept(Visitor $visitor) 94 { 95 $visitor->visitConcreteElementA($this); 96 } 97 } 98 99 /** 100 * 具体元素B 101 */ 102 class ConcreteElementB implements Element { 103 private $_name; 104 105 public function __construct($name) 106 { 107 $this->_name = $name; 108 } 109 110 public function getName() 111 { 112 return $this->_name; 113 } 114 115 /** 116 * @param Visitor $visitor 接受访问者调用它针对该元素的新方法 117 */ 118 public function accept(Visitor $visitor) 119 { 120 $visitor->visitConcreteElementB($this); 121 } 122 } 123 124 125 126 127 /** 128 * 对象结构 即元素的集合 129 */ 130 class ObjectStructure { 131 private $_collection; //具体的元素的集合 132 133 public function __construct() 134 { 135 $this->_collection = []; 136 } 137 138 public function attach(Element $element) { 139 return array_push($this->_collection, $element); 140 } 141 142 public function detach(Element $element) { 143 $index = array_search($element, $this->_collection); 144 145 if ($index !== FALSE) { 146 unset($this->_collection[$index]); 147 } 148 return $index; 149 } 150 151 /** 152 * 访问者可以访问这些元素集合 153 * 154 * @param Visitor $visitor 155 */ 156 public function accept(Visitor $visitor) { 157 foreach ($this->_collection as $element) { 158 $element->accept($visitor); 159 } 160 } 161 } 162 163 164 165 // client 166 $elementA = new ConcreteElementA("小花"); 167 $elementB = new ConcreteElementB("云彩"); 168 169 $visitor1 = new ConcreteVisitor1("路人甲"); 170 $visitor2 = new ConcreteVisitor2("流氓乙"); 171 172 $os = new ObjectStructure(); 173 $os->attach($elementA); 174 $os->attach($elementB); 175 176 $os->accept($visitor1); 177 $os->accept($visitor2); 178 179 180 181 /* 182 哈哈, 小妞(小花), 给本大爷(路人甲)笑一个 183 哈哈, 小妞(云彩), 给本大爷(路人甲)笑一个 184 哈哈, 小妞(小花), 给本大爷(流氓乙)笑一个 185 哈哈, 小妞(云彩), 给本大爷(流氓乙)笑一个 186 */