关于模式本身的概念,请参考网上其它文章
此处只讨论在PHP实际开发过程中的应用
此模式适用范围极为受限,适用情景:
1.适用于项目维护过程,不适用于项目开发过程
2.新增需求,要求为一个/多个类增加一个/多个,相同/相似的方法
3.原有代码不能修改或扩展
4.原有类已经预留了一个为本模式准备的接口.
以上,3,4很难同时在产品维护过程中同时出现.
需求:
1.一组对象,同属一个父类或分属不同父类,使用某一数据结构组成一个数据集,此处的数据结构可以是概念意义上的队列,栈,集合,树,图或实际意义上的一维或多维数组,只要可以遍历即可
2.项目需要对以上对象增加一个操作,以便在遍历整组对象时,同名调用.
实现过程:
1.原有代码中,以上对象所属的类,事先预留了一个扩展接口,可以叫做accept(奇怪的名字)
Class ElementA{
public function accept(VisitorBase $v){
$v->visitA($this);
}
}
class ElementB{
public function accept(VisitorBase $v){
$v->visitB($this);
}
}
根据以上,我们当然要事先定义一个VisitorBase的抽象接口
interface VisitorBase {
function visitA(ElementA $eleA);
function visitB(ElementB $eleB);
}
2.新的代码中,我们为新增的操作创建一个类,叫做VisitorX(访问者,又是一个奇怪的名称),如果有另一个操作,可以定义为VisitorY,均实现了VisitorBase接口
class VisitorX implements VisitorBase{
public function visitA(ElementA $eleA){
//此处可以访问元素A的方法以处理具体事务
$eleA->someFunc();
}
public function visitB(ElementB $eleB){
……
}
}
3.新的代码中,我们可以遍历,以数组为例(这个最常用了)
$x=new VisitorX;
foreach($elementArray as $element){
$element->accept($x);
}
以上将遍历所有元素(无论是否同一父类),对每一个元素执行VisitorX类中的相应操作.
草根观点:
1.凭什么原有代码不让修改?只是加个方法而已.
2.我不改原有代码,还不让我继承一下,扩展一个方法?
3.原有代码定义扩展接口了么?以前的程序员有这么前瞻?
4.只要有其它方式实现同等功能,尽量不要使用此设计模式, 这将导致对同一对象的操作代码分散在程序的不同位置,不利于进一步的维护与修改.
5.可考虑的替代实现方法:
A.修改原有类,增加一个同名方法
B.扩展(继承)原有类,增加一个同名方法
C.如果一定要将不同类的同一操作的代码集中在一起,那么考虑Trait吧