观察者模式,就是在主任务之外的辅助任务,及不影响主任务,也可以随意增减辅助任务,方便需求修改,也是维持代码整洁易读的好方法。
登录是一个典型的例子,我们处理登录任务时,除了判断用户登录成功、失败的信息之外,还要记录用户登录失败的信息,登录日志处理,或者产品的特殊需求,某个用户登录发个邮件啥的
还有某个用户发了一条消息,给特别关注用户发提醒等等吧
如果这些都写在过程里,会影响代码执行,某一天你会发现代码很长了还在增长。那么观察者模式是一个解决这个问题的很好的工具。
下面我们自己写一个观察者模式,当然php系统提供管缠着模式的封装。
<?php
interface Observable{
function attach(Observer $observer);
function detach(Observer $observer);
function notify();
}
class Login implements Observable{
private $observers;
const LOGIN_USER_UNKONWN = 1;
const LOGIN_WRONG_PASS = 2;
const LOGIN_ACCESS = 3;
private $status = array();
function __construct(){
$this->observers= array();
}
function attach(Observer $observer){
$this->observers[]=$observer;
}
function detach(Observer $observer)
{
$this->observers = array_udiff($this->observers,array($observer),
function($a,$b){ if($a===$b){return false;}else{ return true;}});
}
function notify(){
foreach($this->observers as $observer)
{
$observer->update($this);
}
}
function handleLogin($user, $pass, $ip)
{
switch(rand(1,3)){
case 1:
$this->setStatus(self::LOGIN_ACCESS,$user,$ip);
$ret = true;break;
case 2:
$this->setStatus(self::LOGIN_WRONG_PASS,$user,$ip);
$ret = false;break;
case 3:
$this->setStatus(self::LOGIN_USER_UNKONWN,$user,$ip);
$ret = false;break;
}
$this->notify();
return $ret;
}
private function setStatus($status, $user,$ip){
$this->status = array($status, $user,$ip);
}
function getStatus(){
return $this->status;
}
}
interface Observer{
function update(Observable $observer);
}
abstract class LoginObserver implements Observer{
private $login;
function __construct(Login $login){
$this->login = $login;
$login->attach($this);
}
function update(Observable $observer){
if($observer === $this->login)
{
$this->doUpdate($observer);
}
}
abstract function doUpdate(Login $login);
}
class SecurityMoniter extends LoginObserver{
function doUpdate(Login $login){
$status = $login->getStatus();
if($status[0] == Login::LOGIN_WRONG_PASS)
{
print __CLASS__.":\t send email to sysadmin\n";
}
}
}
class GeneralLogger extends LoginObserver{
function doUpdate(Login $login)
{
$status = $login->getStatus();
print __CLASS__.".\t add login data to log\n";
}
}
class PartnerShipTool extends LoginObserver{
function doUpdate(Login $login)
{
$status = $login->getStatus();
print __CLASS__."\t set cookie if IP matches a list\n";
}
}
$login = new Login();
$securityMoniter = new SecurityMoniter($login);
$generalLogger = new GeneralLogger($login);
$partnerShipTool = new PartnerShipTool($login);
$login->handleLogin("admin", "12345", "127.0.0.1");
运行结果:
SecurityMoniter: send email to sysadmin
GeneralLogger. add login data to log
PartnerShipTool set cookie if IP matches a list