访问者模式——操作与数据结构分离

什么是访问者模式
在《设计模式》中是这么定义的:访问者模式表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

可以看出,相比通过调用对象方法来对对象进行操作,访问者模式将操作和对象进行解耦,使得操作与对象相互独立,可以很容易得实现操作的修改和增减。

下面通过公园收费规则的场景来进行演示访问者模式。
假设进入公园游玩的费用受到游客类型(老人,小孩会有优惠)和旅游时间段(淡季,旺季)的影响。在这个例子中,小孩,老年人和普通游客是具体元素,不同的旅游时间段是访问者。

首先我们先来定义抽象游客类(抽象元素)

abstract class tourist{
    //接受访问者访问,实际上就是调用传入访问者的方法
    abstract function accept(visitor $visitor);
}

具体游客类(具体元素)

class older extends tourist {
    function accept(visitor $visitor)
    {
        $visitor->visitOlder();
    }
}
class kids extends tourist {
    function accept(visitor $visitor)
    {
        $visitor->vistitKids();
    }
}
class adult extends tourist {
    function accept(visitor $visitor)
    {
        $visitor->visitAdult();
    }
}

抽象访问者类,定义了访问不同元素的接口,在这里可以看出访问者模式的局限,当需要访问的对象结构类中对象类型不确定或者经常变动时,需要对该类及其子类进行改动,不符合开放封闭原则,所以说访问者模式比较适合数据结构比较稳定的系统。

abstract class visitor{
   abstract function visitOlder();
   abstract function vistitKids();
   abstract function visitAdult();
}

旺季收费类(具体访问者类),具体实现对对象结构中不同元素的操作

class busySeason extends visitor {
    function visitOlder()
    {
        echo "旺季老人依旧免费<br>";
    }
    function vistitKids()
    {
        echo "旺季小孩半票<br>";
    }
    function visitAdult()
    {
        echo "旺季成年人票价*1.5<br>";
    }
}

淡季收费类

class slackSeason extends visitor{
    function visitOlder()
    {
        echo "淡季老人免费<br>";
    }

    function vistitKids()
    {
        echo "淡季小孩也免费<br>";
    }
    function visitAdult()
    {
        echo "淡季成年人全票<br>";
    }
}

对象结构类

class touristSet{
    private $touristList=array();
    public function addTourist(tourist $tourist){
        $this->touristList[]=$tourist;
    }
    //接受不同的访问者的访问时,对对象集中的元素执行不同的操作
    public function showStrategy(visitor $visitor){
        foreach ($this->touristList as $tourist) {
            $tourist->accept($visitor);
        }
    }
}

客户端代码:

//实例化元素
$kids=new kids();
$older=new older();
$adult=new adult();
//构造对象结构
$park=new touristSet();
$park->addTourist($kids);
$park->addTourist($older);
$park->addTourist($adult);
//实例化访问者
$busy=new  busySeason();
$slack=new slackSeason();
//不同的访问者对对象结构中的元素进行遍历访问
$park->showStrategy($busy);
$park->showStrategy($slack);

这里写图片描述
总结
可以看出,访问者模式由抽象元素类,具体元素,具体元素集,抽象访问类,具体访问者组成,操作的执行实际上是通过调用访问者的方法实现的,通过切换不同的访问者来切换对素集中的元素的操作。从另一个角度来看,如果定义的不同的访问者分别实现了算法中的不同环节,我们通过客户端依次让元素接受这些访问者的访问,从而能够实现一个完整的算法,这样的好处是显而易见的,我们即可以对算法中的每个环节进行增删,也可以灵活得调整每个环节的具体实现。总的来说访问者模式用的属于比较少的那种,因为对系统数据结构的稳定性有严格的要求,假设系统中由操作来区分的对象不是固定的,那么要调整的时候需要对访问者进行大量的修改,这样是不符合开放封闭原则的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值