观察者模式属于行为模式的一种,他的核心思想是把观察者从一个中心类(主体)中分离出来,在主体发生一个事件时,通知到对应的观察者。特别是当一个主体发生的事件需要通知到多个观察者,而我们又不想将主题与观察者进行硬编码绑定在一起时应该考虑实现观察者模式。
关于观察者模式实现的契机,上边已经有所提及了,再简而言之就是:当对象间出现一对多的关系时,观察者模式应该被实现。
php
<?php
/**
* 定义观察者事件(主体)对象的基类
* Interface Observable
*/
Interface Observable
{
public function attach(Observer $observe);
public function detach(Observer $observe);
public function notify();
}
/**
* 定义主体事件类,接口的一个实现
* Class Login
*/
class Login implements Observable
{
const LOGIN_USER_UNKNOWN = 1;
const LOGIN_WRONG_PASS = 2;
const LOGIN_ACCESS = 3;
private $status = [];
private $observes = [];
/**
* 观察者类的具体调用实现。
* @param $user
* @param $pass
* @param $ip
* @return bool
*/
public function handleLogin($user,$pass,$ip)
{
switch (rand(1, 3)) {
case 1:
$this->setStatus(self::LOGIN_ACCESS);
$ret = true;
break;
case 2:
$this->setStatus(self::LOGIN_WRONG_PASS);
$ret = false;
break;
case 3:
$this->setStatus(self::LOGIN_USER_UNKNOWN);
$ret = false;
break;
}
$this->notify();
return $ret;
}
/**
* 添加观察者对象
* @param Observer $observe
*/
public function attach(Observer $observe)
{
$this->observes[] = $observe;
}
/**
* 删除观察者对象
* @param Observer $observe
*/
public function detach(Observer $observe)
{
$newObserves = [];
foreach ($this->observes as $obs) {
if ($observe !== $obs) {
$newObserves[] = $obs;
}
}
$this->observes = $newObserves;
}
/**
* 通知观察者事件的更新
*/
public function notify()
{
foreach ($this->observes as $observe) {
$observe->update($this);
}
}
public function setStatus($status)
{
$this->status = $status;
}
public function getStatus()
{
return $this->status;
}
}
/**
* 定义观察者类接口
* Interface Observer
*/
Interface Observer
{
public function update(Observable $observable);
}
/**
* 强化观察者类的基础功能
* Class LoginObserver
*/
abstract class LoginObserver implements Observer
{
private $login;
public function __construct(Login $login)
{
$this->login = $login;
}
public function update(Observable $observable)
{
if ($observable = $this->login) {
$this->doUpdate($observable);
}
}
abstract function doUpdate(Login $login);
}
class SecurityMonitor extends LoginObserver
{
function doUpdate(Login $login)
{
$status = $login->getStatus();
if ($status[0] == Login::LOGIN_WRONG_PASS) {
//TODO 密码错误的处理逻辑
}
}
}
class GeneralLogger extends LoginObserver
{
function doUpdate(Login $login)
{
$status = $login->getStatus();
//TODO 处理日志记录的处理逻辑
}
}
//添加观察者对象
$login = new Login();
new SecurityMonitor($login);
new GeneralLogger($login);
//调用观察者通知处理函数,此处登录时调用handleLogin()方法函数会自动进行通知处理
//$login->notify();