PHP设计模式之观察者模式

PHP设计模式之观察者模式

观察者,貌似在不少科幻做品中都会有这个角色的出现。好比我很喜欢的一部美剧《危机边缘》,在这个剧集中,观察者不停的穿越时空记录着各类各样的人或事。可是,设计模式中的观察者可不仅是站在边上看哦,这里的观察者是针对主体发生的状态改变来作出对应的动做。php

Gof类图及解释

GoF定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,全部依赖于它的对象都获得通知并被自动更新git

GoF类图github

适配器方法结构类图-继承式

代码实现数据库

interface Observer {
    public function update(Subject $subject): void;
}
复制代码

观察者的抽象接口,没啥可说的吧,就是让你实现一个具体的Update就能够了编程

class ConcreteObserver implements Observer {
    private $observerState = '';
    function update(Subject $subject): void {
        $this->observerState = $subject->getState();
        echo '执行观察者操做!当前状态:' . $this->observerState;
    }
}
复制代码

具体的观察者,实现update()方法,这里咱们拿到了Subject类,从而能够得到其中的状态设计模式

class Subject {
    private $observers = [];
    private $stateNow = '';
    public function attach(Observer $observer): void {
        array_push($this->observers, $observer);
    }
    public function detach(Observer $observer): void {
        $position = 0;
        foreach ($this->observers as $ob) {
            if ($ob == $observer) {
                array_splice($this->observers, ($position), 1);
            }
            ++$position;
        }
    }
    public function notify(): void {
        foreach ($this->observers as $ob) {
            $ob->update($this);
        }
    }
}
复制代码

Subject父类,维护一个观察者数组,而后有添加、删除以及循环遍历这个数组的方法,目的是可以方便的管理全部的观察者数组

class ConcreteSubject extends Subject{
    public function setState($state) {
        $this->stateNow = $state;
        $this->notify();
    }

    public function getState() {
        return $this->stateNow;
    }
}
复制代码

Subject的实现类,只是更新了状态,在这个状态发生改变的时候,调用观察者遍历的方法进行全部观察的update()操做编程语言

  • 观察者,其实就是自身作了一个更新(update),而Subject,能够批量的执行观察者,请注意,咱们不须要去修改目标类中的任何代码,只须要从外部添加就能够了,因此就让目标和观察者解耦互相之间不用关心对方的状况了
  • 观察者能够记录目标的状态,也能够不用记录,好比咱们发完短信后的数据库更新或者插入操做,只有短信接口发送成功后咱们再修改短信数据的状态就能够了,不必定彻底须要将目标的发送状态传送给观察者
  • 当一个类在发生改变时,不知道可能会对其余多少类产生影响,这个时候观察者很是有用
  • 观察者模式中仍是存在着耦合,那就是目标类中有一个观察者对象列表,若是观察者没有实现update()方法,那么就会出现问题

接着拿咱们的手机工厂说事儿,此次好嘛,被一帮山寨机盯上了(观察者),我出什么功能(状态更新),他们就对应的出同样的功能(更新),并且还在个人基础上作了更多的东西,美其名曰:微创新!你说气人不气人。好吧,我也派出了一帮市场调查人员(观察者),去帮我观察别人家的手机都出了什么功能(状态更新),而后咱们也照搬过来搞点微创新,你们共同进步嘛!!this

完整代码:github.com/zhangyue050…spa

实例

此次咱们从订单提及,不过仍是有短信发送的事儿。当通常的电商平台有人下单以后,须要作的事情很是多,好比修改库存、发送短信或者推送告诉商家有人下单了,告诉买家下单成功了,支付成功了。总之就是一件事情的发生会致使各类事件的产生。其实,这里就引出了另外一个很是出名的模式订阅发布模式。这个模式能够说是观察者的升级模式,这个系列的文章不会细讲,可是你们能够去看看Laravel中的发布订阅事件监听方面的内容。

订单售出类图

订单售出观察者模式

完整源码:github.com/zhangyue050…

interface Observer {
    public function update($obj);
}

class Message implements Observer {
    //....

    function update($obj) {
        echo '发送新订单短信(' . $obj->mobile . ')通知给商家!';
    }

    //....
}

class Goods implements Observer {
    //....

    public function update($obj) {
        echo '修改商品' . $obj->goodsId . '的库存!';
    }

    //....
}

class Order {
    private $observers = [];
    public function attach($ob) {
        $this->observers[] = $ob;
    }

    public function detach($ob) {
        $position = 0;
        foreach ($this->observers as $ob) {
            if ($ob == $observer) {
                array_splice($this->observers, ($position), 1);
            }
            ++$position;
        }
    }
    public function notify($obj) {
        foreach ($this->observers as $ob) {
            $ob->update($obj);
        }
    }
    public function sale() {
        // 商品卖掉了
        // ....
        $obj = new stdClass();
        $obj->mobile = '13888888888';
        $obj->goodsId = 'Order11111111';
        $this->notify($obj);
    }
}

$message = new Message();
$goods = new Goods();
$order = new Order();
$order->attach($message);
$order->attach($goods);

// 订单卖出了!!
$order->sale();

复制代码

说明

  • 咱们没有彻底的遵照GoF类图,虽然说GoF是圣经,但也并非咱们必需要彻底遵照的,咱们能够针对具体的业务状况进行合适的裁剪使用
  • 订单状态经过sale()方法产生变化后,直接调用notify方法进行观察者的调用
  • 发短信、发推送均可以拆开由一个一个的观察者来实现,这些观察者不必定只有这一个方法,但只要实现共同的接口就能够了
  • 商品库存和消息发送其实就是两个自己彻底不沾边的类,但它们只须要实现同样的接口就好啦
  • PHP的SPL扩展中已经为咱们准备好了一套观察者接口,你们能够试试哦,使用原生支持的观察者模式能省很多事儿呢!

SPL扩展实现观察者模式-完整源码:github.com/zhangyue050…

下期看点

循环是编程语言的一个亮点,由于这个能力让编程语言作出来的软件能够替代人们去作不少重复的劳动。一说到这里,有的人立刻就会想到,莫非咱们下次讲的就是迭代器模式?拭目以待吧!

相关文章
相关标签/搜索