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