PHP – 观察者模式

一、概述

  一个事件发生后,要执行一连串更新操作。传统的编程方式就是在事件的代码之后直接加入处理逻辑,当更新的逻辑增多之后,代码会变的难以维护。这种方式是耦合的,侵入式的,增加新的逻辑需要修改事件主体的代码。

  观察者模式实现了低耦合,非侵入式的通知与更新机制。

 

二、PHP 代码

<?php
declare(strict_types = 1);

/**
 * 观察者模式场景描述:
 * 1、购票后记录文本日志
 * 2、购票后记录数据库日志
 * 3、购票后发送短信
 * 4、购票送抵扣卷、兑换卷、积分
 */


/**
 * 观察者接口
 */
interface TicketObserver
{
    function buyTicketOver($sender, $args); //得到通知后调用的方法
}

/**
 * 被观察者接口(购票主题接口)
 */
interface TicketObserved
{
    function addObserver($observer); //提供注册观察者方法
}


/**
 * 主体逻辑,继承被观察者接口
 * Class BuyTicket
 */
class BuyTicket implements TicketObserved
{

    /**
     * 定义观察者数组属性,用于储存观察者
     * @var array
     */
    private $observers = array();

    /**
     * 实现被观察者接口定义的方法(添加观察者)
     * @param $observer '实例化后的观察者对象'
     */
    public function addObserver($observer)
    {
        $this->observers[] = $observer;
    }

    /**
     * 购票主体方法
     * BuyTicket constructor.
     * @param $ticket '购票排号'
     */
    public function buyTicketAction($ticket)
    {
        //1、根据需求写购票逻辑
        //..............

        //2、购票成功之后,循环通知观察者,并调用其buyTicketOver实现不同业务逻辑
        foreach ($this->observers as $observe) {
            $observe->buyTicketOver($this, $ticket); //$this 可用来获取主题类句柄,在通知中使用
        }
    }
}

/**
 * 购票成功后,发送短信通知
 * Class buyTicketMSN
 */
class buyTicketMSN implements TicketObserver
{
    public function buyTicketOver($sender, $ticket)
    {
        echo (date ( 'Y-m-d H:i:s' ) . " 短信日志记录:购票成功:$ticket<br>");
    }
}


/**
 * 购票成功后,记录日志
 * Class buyTicketLog
 */
class buyTicketLog implements TicketObserver
{
    public function buyTicketOver($sender, $ticket)
    {
        echo (date ( 'Y-m-d H:i:s' ) . " 文本日志记录:购票成功:$ticket<br>");
    }
}


/**
 * 购票成功后,赠送优惠券
 * Class buyTicketCoupon
 */
class buyTicketCoupon implements TicketObserver
{
    public function buyTicketOver($sender, $ticket)
    {
        echo (date ( 'Y-m-d H:i:s' ) . " 赠送优惠券:购票成功:$ticket 赠送10元优惠券1张。<br>");
    }
}


//实例化购票类
$buy = new BuyTicket();

//添加多个观察者
$buy->addObserver(new buyTicketMSN());
$buy->addObserver(new buyTicketLog());
$buy->addObserver(new buyTicketCoupon());

//开始购票
$buy->buyTicketAction("7排8号");
// 结果
2019-08-14 00:29:34 短信日志记录:购票成功:7排8号
2019-08-14 00:29:34 文本日志记录:购票成功:7排8号
2019-08-14 00:29:34 赠送优惠券:购票成功:7排8号 赠送10元优惠券1张。

 

三、说明

  对于必须实时更新的操作,适合用观察者模式这种操作,实现了代码的低耦合。

  但是如果要求是最终一致性,而不是强一致性,这时,可以考虑消息队列来实现。触发了这个方法,并且这个方法执行成功后,推一系列的队列,慢慢在后台执行。(其实并不慢,顶多差2 ~ 3 秒。)