PHP设计模式之访问者模式

PHP设计模式之访问者模式

访问者,就像咱们去别人家访问,或者别人来咱们家看望咱们同样。咱们每一个人都像是一个实体,而来访的人都会一一的和咱们打招呼。毕竟,咱们中华民族是很是讲究礼数和好客的民族。访问者是GoF23个设计模式中最复杂的一个模式,也是各种设计模式教材都放在最后的一个模式。先无论难度如何,咱们先看看它的定义和实现。php

Gof类图及解释

GoF定义:表示一个做用于某对象结构中的各元素的操做。它使你能够在不改变各元素的类的前提下定义做用于这些元素的新操做git

GoF类图github

访问者模式

代码实现设计模式

interface Visitor {
    public function VisitConcreteElementA(ConcreteElementA $a);
    function VisitConcreteElementB(ConcreteElementB $b);
}

class ConcreteVisitor1 implements Visitor {
    public function VisitConcreteElementA(ConcreteElementA $a) {
        echo get_class($a) . "被" . get_class($this) . "访问", PHP_EOL;
    }
    public function VisitConcreteElementB(ConcreteElementB $b) {
        echo get_class($b) . "被" . get_class($this) . "访问", PHP_EOL;
    }
}

class ConcreteVisitor2 implements Visitor {
    public function VisitConcreteElementA(ConcreteElementA $a) {
        echo get_class($a) . "被" . get_class($this) . "访问", PHP_EOL;
    }
    public function VisitConcreteElementB(ConcreteElementB $b) {
        echo get_class($b) . "被" . get_class($this) . "访问", PHP_EOL;
    }
}
复制代码

抽象的访问者接口及两个具体实现。能够看做是一家小两口来咱们家做客咯!数据结构

interface Element {
    public function Accept(Visitor $v);
}

class ConcreteElementA implements Element {
    public function Accept(Visitor $v) {
        $v->VisitConcreteElementA($this);
    }
    public function OperationA() {

    }
}

class ConcreteElementB implements Element {
    public function Accept(Visitor $v) {
        $v->VisitConcreteElementB($this);
    }
    public function OperationB() {

    }
}
复制代码

元素抽象及实现,也能够看做是要访问的实体。固然就是我和我媳妇啦。学习

class ObjectStructure {
    private $elements = [];

    public function Attach(Element $element) {
        $this->elements[] = $element;
    }

    public function Detach(Element $element) {
        $position = 0;
        foreach ($this->elements as $e) {
            if ($e == $element) {
                unset($this->elements[$position]);
                break;
            }
            $position++;
        }
    }

    public function Accept(Visitor $visitor) {
        foreach ($this->elements as $e) {
            $e->Accept($visitor);
        }
    }

}
复制代码

这是一个对象结构,用于保存元素实体并进行访问调用。你们在客厅里见面,互相寒暄嘛,这里就是个客厅this

$o = new ObjectStructure();
$o->Attach(new ConcreteElementA());
$o->Attach(new ConcreteElementB());

$v1 = new ConcreteVisitor1();
$v2 = new ConcreteVisitor2();

$o->Accept($v1);
$o->Accept($v2);
复制代码

客户端的调用,总算让你们正式见面了,互相介绍握手。一次访问就愉快的完成了。阿里云

  • 让访问者调用指定的元素。这里须要注意的,访问者调用元素的行为通常是固定的,不多会改变的。也就是VisitConcreteElementA()、VisitConcreteElementB()这两个方法。也就是定义对象结构的类不多改变,但常常须要在此结构上定义新的操做时,会使用访问者模式
  • 须要对一个对象结构中的对象进行不少不一样的而且不相关的操做,而你想避免让这些操做“污染”这些对象的类时,适用于访问者模式
  • 访问者模式适合数据结构不变化的状况。因此,它是一种日常你用不上,但一旦须要的时候就只能用这种模式的模式。GoF:“大多时候你并不须要访问者模式,但当一旦你须要访问者模式时,那就是真的须要它了”。由于不多有数据结构不发生变化的状况
  • 访问者模式的一些优缺点:易于增长新的操做;集中相关的操做而分离无关的操做;增长新的ConcreteElement类很困难;经过类层次进行访问;累积状态;破坏封装

咱们公司的帐务,只有收入和支出两项(Element),可是不一样的部门(Visitor)访问的时候会给出不一样的内容。好比我查看的时候只须要查看每个月或每季度的汇总数据便可,财务总监则须要详细的收支记录,而会计在作帐时更是须要完整的明细。可见,公司的运营还真的是须要很是普遍的知识的,不只是管理能力,帐务知识也是必要了解的内容!!spa

完整代码:github.com/zhangyue050…设计

实例

最后一个模式的例子仍是回到咱们的信息发送上来。一样的仍是多个服务商,它们做为访问者须要去使用各自的短信发送及APP推送接口。这时,就可使用访问者模式来进行操做,实现这些访问者的所有操做。

访问者模式信息发送

访问者模式信息发送

完整源码:github.com/zhangyue050…

<?php

interface ServiceVisitor {
    public function SendMsg(SendMessage $s);
    function PushMsg(PushMessage $p);
}

class AliYun implements ServiceVisitor {
    public function SendMsg(SendMessage $s) {
        echo '阿里云发送短信!', PHP_EOL;
    }
    public function PushMsg(PushMessage $p) {
        echo '阿里云推送信息!', PHP_EOL;
    }
}

class JiGuang implements ServiceVisitor {
    public function SendMsg(SendMessage $s) {
        echo '极光发送短信!', PHP_EOL;
    }
    public function PushMsg(PushMessage $p) {
        echo '极光推送短信!', PHP_EOL;
    }
}

interface Message {
    public function Msg(ServiceVisitor $v);
}

class PushMessage implements Message {
    public function Msg(ServiceVisitor $v) {
        echo '推送脚本启动:';
        $v->PushMsg($this);
    }
}

class SendMessage implements Message {
    public function Msg(ServiceVisitor $v) {
        echo '短信脚本启动:';
        $v->SendMsg($this);
    }
}

class ObjectStructure {
    private $elements = [];

    public function Attach(Message $element) {
        $this->elements[] = $element;
    }

    public function Detach(Message $element) {
        $position = 0;
        foreach ($this->elements as $e) {
            if ($e == $element) {
                unset($this->elements[$position]);
                break;
            }
            $position++;
        }
    }

    public function Accept(ServiceVisitor $visitor) {
        foreach ($this->elements as $e) {
            $e->Msg($visitor);
        }
    }

}

$o = new ObjectStructure();
$o->Attach(new PushMessage());
$o->Attach(new SendMessage());

$v1 = new AliYun();
$v2 = new JiGuang();

$o->Accept($v1);
$o->Accept($v2);

复制代码

说明

  • 咱们假定发送短信和发送推送是不变的两个行为,也就是它们俩的数据结构是稳定不变的
  • 这样咱们就能够方便的增长ServiceVisitor,当增长百度云或者别的什么短信提供商时,就很方便的增长访问者就能够了
  • 访问者模式比较适合数据结构稳定的结构。好比账单只有收入支出、人的性别只有男女等

下期看点

至此,设计模式部分咱们已经所有学习完了。其实还少了一个解释器模式,但这个模式确实是真的的很是少见,有兴趣的朋友能够自行去了解哈。

相关文章
相关标签/搜索