怎么理解?
从生活中例子来理解:
例子1:
员工1,员工2,员工3 ....; 老板 ; 前台同事;
员工1,2,3委托前台同事如果老板回来了,就通知他们几个;这里 员工就是观察者,收到通知后立即采取动作; 前台同事是被观察者,她的能力是添加通知对象(员工),移除某个“通知对象(员工)”,通知能力; 老板是触发前台通知的条件。
从常见的代码的业务逻辑来理解:
登录类,有时业务比较复杂,或者后期不断的需求增加如:加日志,加邮件通知,加IP过滤等等。都写在一个类中必然很庞大,易出错,难维护。 所以核心登录功能作为一个类(被观察者类); 加日志类,加邮件类等作为观察类。
php 代码如下:
<?php
/**
* Created by PhpStorm.
* User: zhaozhiliang
* Date: 2018/6/6
* Time: 上午10:57
*/
interface Observable{
function attach(Observer $observer);
function detach(Observer $observer);
function notify();
}
class Login implements Observable {
private $observers;
const LOGIN_USER_UNKNOWN = 1;
const LOGIN_WRONG_PASS =2;
const LOGIN_ACCESS = 3;
private $status = array();
function __construct()
{
$this->observers = array();
}
function attach(Observer $observer)
{
// TODO: Implement attach() method.
$this->observers[] = $observer;
}
function detach(Observer $observer)
{
// TODO: Implement detach() method.
$newobservers = array();
foreach ($this->observers as $obs){
if( $obs !== $observer){
$newobservers[] = $obs;
}
}
$this->observers = $newobservers;
}
function notify()
{
// TODO: Implement notify() method.
foreach($this->observers as $obs){
$obs->update($this);
}
}
function handleLogin($user, $pass , $ip){
/**
* 实际上使用存储机制来验证用户数据。这个例子用rand()函数来模拟登录过程。
*/
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_UNKNOWN, $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 $observable);
}
class SecurityMonitor implements Observer {
function update(Observable $observable)
{
// TODO: Implement update() method.
$status = $observable->getStatus();
if($status[0] == Login::LOGIN_WRONG_PASS){
//发送邮件给系统管理员
print __CLASS__.":\tsending mail to sysadmin\n";
}
}
}
class GeneralLogger implements Observer{
function update(Observable $observable)
{
// TODO: Implement update() method.
$staus = $observable->getStatus();
//记录登录数据到日志
print __CLASS__.":\tadd login data to log\n";
}
}
class PartnershipTool implements Observer{
function update(Observable $observable)
{
// TODO: Implement update() method.
$status = $observable->getStatus();
print __CLASS__.":\tset cookie if IP matches a list\n";
}
}
$login = new Login();
$login->attach(new SecurityMonitor());
$login->attach(new GeneralLogger());
$login->attach(new PartnershipTool());
$login->handleLogin('zhangsan','123456','127.0.0.1');
使用SPL库后的代码
<?php
/**
*
*/
class Login implements SplSubject{
private $storage;
const LOGIN_USER_UNKNOWN = 1;
const LOGIN_WRONG_PASS =2;
const LOGIN_ACCESS = 3;
private $status = array();
function __construct()
{
$this->storage = new SplObjectStorage();
}
function attach(SplObserver $observer)
{
// TODO: Implement attach() method.
$this->storage->attach($observer);
}
function detach(SplObserver $observer)
{
// TODO: Implement detach() method.
$this->storage->detach($observer);
}
function notify()
{
// TODO: Implement notify() method.
foreach ($this->storage as $obs){
$obs->update($this);
}
}
function handleLogin($user, $pass , $ip){
/**
* 实际上使用存储机制来验证用户数据。这个例子用rand()函数来模拟登录过程。
*/
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_UNKNOWN, $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;
}
}
abstract class LoginObserver implements SplObserver{
private $login;
function __construct(Login $login)
{
$this->login = $login;
$login->attach($this);
}
function update(SplSubject $subject){
if($subject === $this->login){
$this->doUpdate($subject);
}
}
abstract function doUpdate(Login $login);
}
class SecurityMonitor extends LoginObserver{
function doUpdate(Login $login)
{
// TODO: Implement doUpdate() method.
$status = $login->getStatus();
if($status[0] == Login::LOGIN_WRONG_PASS){
//发送邮件给系统管理员
print __CLASS__.":\tsending mail to sysadmin\n";
}
}
}
class GeneralLogger extends LoginObserver{
function doUpdate(Login $login)
{
// TODO: Implement doUpdate() method.
$status = $login->getStatus();
//记录登录数据到日志
print __CLASS__.":\tadd login data to log\n";
}
}
class PartnershipTool extends LoginObserver{
function doUpdate(Login $login)
{
// TODO: Implement doUpdate() method.
//检查IP地址
//如果地址匹配则,设置cookie
print __CLASS__.":\tset cookie if IP matches a list\n";
}
}
$login = new Login();
//$login->attach(new SecurityMonitor($login));
new SecurityMonitor($login);
new GeneralLogger($login);
new PartnershipTool($login);
$login->handleLogin('zhangsan','123456','127.0.0.1');