【PHP设计模式】行为型之观察者(Observer)
观察者模式:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
允许一个类观察另一个类的状态,当被观察者的类发生改变时,观察类可以收到通知并作出相应的动作。
<UML>
<示例代码>
class Login { const LOGIN_USER_UNKNOWN = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_ACCESS = 3; private $status = array(); 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_UNKNOWN, $user, $ip );//权限不够 $ret = false; break; } Logger::logIP( $user, $ip, $this->getStatus() );//记录日志 if ( ! $ret ) { Notifier::mailWarning( $user, $ip,$this->getStatus() );//邮件通知 } return $ret; } private function setStatus( $status, $user, $ip ) { $this->status = array( $status, $user, $ip ); } function getStatus() { return $this->status; } } class Notifier {//邮件通知 static function mailWarning( $user, $ip, array $status ) { print "Notifier: $user, ip: $ip status:"; print implode("/", $status); print "\n"; } } class Logger {//记录日志 static function logIP( $user, $ip, array $status ) { print "Loggger: $user, ip: $ip status:"; print implode("/", $status); print "\n"; } } $login = new Login(); for ( $x=1; $x<2; $x++ ) { $login->handleLogin( "bob","mypass", '158.152.55.35' ); }
这里的login类实现了太多的功能,和系统的代码仅仅耦合起来了,如果它调用的对象发生改变。
<示例代码二>
/** * 被观察者 */ interface Observable { function attach( Observer $observer ); function detach( Observer $observer ); function notify(); } /** * 具体的被观察者类 */ class Login implements Observable { private $observers = array(); const LOGIN_USER_UNKNOWN = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_ACCESS = 3; function attach( Observer $observer ) {//添加观察者 $this->observers[] = $observer; } function detach( Observer $observer ) {//删除观察者 $newobservers = array(); foreach ( $this->observers as $obs ) { if ( ($obs !== $observer) ) { $newobservers[]=$obs; } } $this->observers = $newobservers; } function notify() {//更新观察者 foreach ( $this->observers as $obs ) { $obs->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_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 $observer ); } abstract class LoginObserver implements Observer {//抽象登陆类 private $login; function __construct( Login $login ) { $this->login = $login; $login->attach( $this ); } 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 ) { print __CLASS__.":\tsending mail to sysadmin\n"; } } } class GeneralLogger extends LoginObserver {//普通登陆 function doUpdate( Login $login ) { $status = $login->getStatus(); print __CLASS__.":\tadd login data to log\n"; } } class PartnershipTool extends LoginObserver {//合作伙伴登陆 function doUpdate( Login $login ) { $status = $login->getStatus(); print __CLASS__.":\tset cookie if it matches a list\n"; } } $login = new Login(); $SecurityMonitor = new SecurityMonitor( $login ); $GeneralLogger = new GeneralLogger( $login ); $PartnershipTool = new PartnershipTool( $login ); $login->detach( $PartnershipTool ); for ( $x=0; $x<3; $x++ ) { $login->handleLogin( "bob","mypass", '158.152.55.35' ); print "\n"; }
SplSubject:被观察的对象。
/** * 被观察者 */ class Login implements SplSubject { private $storage; const LOGIN_USER_UNKNOWN = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_ACCESS = 3; function __construct() { $this->storage = new SplObjectStorage(); } function attach( SplObserver $observer ) { $this->storage->attach( $observer ); } function detach( SplObserver $observer ) { $this->storage->attach( $observer ); } function notify() { foreach ( $this->storage as $obs ) { $obs->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_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( SplSubject $observer ); } */ /** * 观察者 */ 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 ) { $status = $login->getStatus(); if ( $status[0] == Login::LOGIN_WRONG_PASS ) { print __CLASS__.":安全登录<br>"; } } } class GeneralLogger extends LoginObserver {//普通登陆 function doUpdate( Login $login ) { $status = $login->getStatus(); print __CLASS__.":\t添加日志<br>"; } } class PartnershipTool extends LoginObserver {//合作者登陆 function doUpdate( Login $login ) { $status = $login->getStatus(); print __CLASS__.":\t设置cookie <br>"; } } $login = new Login(); new SecurityMonitor( $login ); new GeneralLogger( $login ); $PartnershipTool = new PartnershipTool( $login ); $login->detach( $PartnershipTool ); for ( $x=0; $x<1; $x++ ) { $login->handleLogin( "bob","mypass", '158.152.55.35' ); }
SplObserver接口,代表观察者的对象。SplSubject维护了一个特定的状态,当这个状态发生改变时,它就用notify()来通知之前注册的SplObserver对象,并且调用其相应的update方法。当然,在观察者类中,也需要有增加和删除观察者类的方法!这里是attach()和detach();
posted on 2014-06-22 15:00 color_story 阅读(190) 评论(0) 编辑 收藏 举报