GoF类图
访问者模式
代码实现

interfaceVisitor{publicfunctionVisitConcreteElementA(ConcreteElementA$a);functionVisitConcreteElementB(ConcreteElementB$b);}classConcreteVisitor1implementsVisitor{publicfunctionVisitConcreteElementA(ConcreteElementA$a){echoget_class($a)."被".get_class($this)."访问",PHP_EOL;}publicfunctionVisitConcreteElementB(ConcreteElementB$b){echoget_class($b)."被".get_class($this)."访问",PHP_EOL;}}classConcreteVisitor2implementsVisitor{publicfunctionVisitConcreteElementA(ConcreteElementA$a){echoget_class($a)."被".get_class($this)."访问",PHP_EOL;}publicfunctionVisitConcreteElementB(ConcreteElementB$b){echoget_class($b)."被".get_class($this)."访问",PHP_EOL;}}
抽象的访问者接口及两个详细实现。可以看作是一家小两口来我们家作客咯!
interfaceElement{publicfunctionAccept(Visitor$v);}classConcreteElementAimplementsElement{publicfunctionAccept(Visitor$v){$v->VisitConcreteElementA($this);}publicfunctionOperationA(){}}classConcreteElementBimplementsElement{publicfunctionAccept(Visitor$v){$v->VisitConcreteElementB($this);}publicfunctionOperationB(){}}
元素抽象及实现,也可以看作是要访问的实体。当然便是我和我媳妇啦。
classObjectStructure{private$elements=[];publicfunctionAttach(Element$element){$this->elements[]=$element;}publicfunctionDetach(Element$element){$position=0;foreach($this->elementsas$e){if($e==$element){unset($this->elements[$position]);break;}$position++;}}publicfunctionAccept(Visitor$visitor){foreach($this->elementsas$e){$e->Accept($visitor);}}}
这是一个工具构造,用于保存元素实体并进行访问调用。大家在客厅里见面,相互寒暄嘛,这里便是个客厅
$o=newObjectStructure();$o->Attach(newConcreteElementA());$o->Attach(newConcreteElementB());$v1=newConcreteVisitor1();$v2=newConcreteVisitor2();$o->Accept($v1);$o->Accept($v2);
客户真个调用,总算让大家正式见面了,相互先容握手。一次访问就愉快的完成了。
让访问者调用指定的元素。这里须要把稳的,访问者调用元素的行为一样平常是固定的,很少会改变的。也便是VisitConcreteElementA()、VisitConcreteElementB()这两个方法。也便是定义工具构造的类很少改变,但常常须要在此构造上定义新的操作时,会利用访问者模式须要对一个工具构造中的工具进行很多不同的并且不干系的操作,而你想避免让这些操作“污染”这些工具的类时,适用于访问者模式访问者模式适宜数据构造不变革的情形。以是,它是一种平常你用不上,但一旦须要的时候就只能用这种模式的模式。GoF:“大多时候你并不须要访问者模式,但当一旦你须要访问者模式时,那便是真的须要它了”。由于很少有数据构造不发生变革的情形访问者模式的一些优缺陷:易于增加新的操作;集中干系的操作而分离无关的操作;增加新的ConcreteElement类很困难;通过类层次进行访问;累积状态;毁坏封装我们公司的账务,只有收入和支出两项(Element),但是不同的部门(Visitor)访问的时候会给出不同的内容。比如我查看的时候只须要查看每月或每季度的汇总数据即可,财务总监则须要详细的进出记录,而司帐在做账时更是须要完全的明细。可见,公司的运营还真的是须要非常广泛的知识的,不仅是管理能力,账务知识也是必要理解的内容!
!
完全代码:https://github.com/zhangyue0503/designpatterns-php/blob/master/23.visitor/source/visitor.php
实例末了一个模式的例子还是回到我们的信息发送上来。同样的还是多个做事商,它们作为访问者须要去利用各自的短信发送及APP推送接口。这时,就可以利用访问者模式来进行操作,实现这些访问者的全部操作。
访问者模式信息发送
访问者模式信息发送
完全源码:https://github.com/zhangyue0503/designpatterns-php/blob/master/23.visitor/source/visitor-msg.php
<?phpinterfaceServiceVisitor{publicfunctionSendMsg(SendMessage$s);functionPushMsg(PushMessage$p);}classAliYunimplementsServiceVisitor{publicfunctionSendMsg(SendMessage$s){echo'阿里云发送短信!
',PHP_EOL;}publicfunctionPushMsg(PushMessage$p){echo'阿里云推送信息!
',PHP_EOL;}}classJiGuangimplementsServiceVisitor{publicfunctionSendMsg(SendMessage$s){echo'极光发送短信!
',PHP_EOL;}publicfunctionPushMsg(PushMessage$p){echo'极光推送短信!
',PHP_EOL;}}interfaceMessage{publicfunctionMsg(ServiceVisitor$v);}classPushMessageimplementsMessage{publicfunctionMsg(ServiceVisitor$v){echo'推送脚本启动:';$v->PushMsg($this);}}classSendMessageimplementsMessage{publicfunctionMsg(ServiceVisitor$v){echo'短信脚本启动:';$v->SendMsg($this);}}classObjectStructure{private$elements=[];publicfunctionAttach(Message$element){$this->elements[]=$element;}publicfunctionDetach(Message$element){$position=0;foreach($this->elementsas$e){if($e==$element){unset($this->elements[$position]);break;}$position++;}}publicfunctionAccept(ServiceVisitor$visitor){foreach($this->elementsas$e){$e->Msg($visitor);}}}$o=newObjectStructure();$o->Attach(newPushMessage());$o->Attach(newSendMessage());$v1=newAliYun();$v2=newJiGuang();$o->Accept($v1);$o->Accept($v2);
解释
我们假定发送短信和发送推送是不变的两个行为,也便是它们俩的数据构造是稳定不变的这样我们就可以方便的增加ServiceVisitor,当增加百度云或者别的什么短信供应商时,就很方便的增加访问者就可以了访问者模式比较适宜数据构造稳定的构造。比如帐单只有收入支出、人的性别只有男女等下期看点至此,设计模式部分我们已经全部学习完了。实在还少了一个阐明器模式,但这个模式确实是真的的非常少见,有兴趣的朋友可以自行去理解哈。