PHP-观察者模式

观察者模式是行为型模式的一种,定义了对象间一对多的关系。当对象(被观察者)的状态发生变化时候,依赖于它的对象(观察者)会得到通知,处理对应的任务。

在PHP的标准库中的使用

在PHP中,提供了方便实现观察者模式的接口,主要包括以下两个:

SplObserver接口:这个接口定义了观察者对象的方法。观察者通过实现这个接口来接收被观察对象的通知。

SplSubject接口:这个接口定义了被观察对象的方法。被观察对象通过实现这个接口来管理观察者的注册、注销和通知。

具体应用

在游戏中,当研发测收到SDK回调,需要通知服务端去发货或者做一些监控处理,可以使用设计模式灵活去实现。

构造被观察者类Order

class Order implements \SplSubject
{
  //存放观察者
  private $observers = null;

  //订单数据
  public $orderData = [], $orderStatus = 0;

  public function __construct()
  {
    $this->observers = new \SplObjectStorage();
  }

  //添加一个观察者
  public function attach(\SplObserver $observer)
  {
    if (!$this->observers->contains($observer)) {
      $this->observers->attach($observer);
    }
  }

  //删除一个观察者
  public function detach(\SplObserver $observer)
  {
    $this->observers->detach($observer);

  }

  //通知观察者
  public function notify()
  {
    if (count($this->observers) > 0) {
      foreach ($this->observers as $observer) {
        // 把本类对象传给观察者,以便观察者获取当前类对象的信息
        $observer->update($this);
      }
    }
  }

  //订单入库
  public function insertOrder($orderData = [])
  {

    echo "后台订单入库操作" . PHP_EOL;
    $res = $this->setOrder($orderData);
    $this->orderData = $orderData;
    $this->orderStatus = $res['code'];
    $this->notify();
    return $res;
  }

  private function setOrder($orderData)
  {
    try {
      if (empty($orderData['money']) || $orderData['money'] < 0) {
        throw new Exception("money error");
      }
      //处理订单入库逻辑
      // TODO: Change the autogenerated stub
      //入库成功返回成功信息
      return ['code' => 1, 'msg' => "success"];

    } catch (\Exception $e) {
      return ['code' => 0, 'msg' => "msg:" . $e->getMessage() . '...line:' . $e->getLine()];
    }
  }

  public function getOrderStatus()
  {
    return $this->orderStatus;
  }

}

构建SyncOrder触发服务端发货观察者

//订单入库更新成功,通知观察者
class SyncOrder implements \SplObserver
{

  public function update(\SplSubject $subject)
  {
    $orderStatus = $subject->getOrderStatus();
    if (!$orderStatus) {
      echo "充值失败,不需要发货,订单信息:" . json_encode($subject->orderData) . ",订单状态:" . $orderStatus . PHP_EOL;
      return;
    }
    echo "后台订单已更新并且入库,给服务端发货,订单信息:" . json_encode($subject->orderData) . ",订单状态:" . $orderStatus . PHP_EOL;

  }
}

构造邮件或者短信消息发送观察者

//订单入库更新成功,通知观察者
class SyncMsg implements \SplObserver
{
  public function update(\SplSubject $subject)
  {
    $orderStatus = $subject->getOrderStatus();
    if (!$orderStatus) {
      echo "充值失败,订单信息:" . json_encode($subject->orderData) . ",订单状态:" . $orderStatus . PHP_EOL;
      return;
    }
    if ($subject->orderData['money'] > 648) {
      echo "后台订单已入库,有大额玩家充值,发送消息,订单信息:" . json_encode($subject->orderData) . ",订单状态:" . $orderStatus . PHP_EOL;
    }

  }
}

使用

//构建被观察者订单对象
$order = new Order();

$syncOrder = new SyncOrder();
$syncMsg = new SyncMsg();

//添加通知服务端发货观察者;
$order->attach($syncOrder);
//添加消息通知观察者;
$order->attach($syncMsg);

//第一笔订单
$orderData = ['order_num' => time(), "uid" => 123456, "money" => 1000];
$order->insertOrder($orderData);

//第二笔订单
$orderData = ['order_num' => time(), "uid" => 123456, "money" => 0];
$order->insertOrder($orderData);