设计模式-观察者模式

<?php
/**
* 观察者模式
* 实现用户登录 并且 记录下log 发送mail如果ip在匹配iplist设置cookie
*
*/

interface Observable{
function attach( Observer $observer );
function detach( Observer $observer );
function notify();
}

class Login implements Observable {
private $observers = array();
const LOGIN_USER_UNKNOW = 1;
const LOGIN_WRONG_PASS = 2;
const LOGIN_ACESS = 3;
private $status = array();
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 );
}
}
/**
* 登录启动器
* 记录登录状态
* return BOOLEAN
*
* */
function handleLogin( $user, $pass, $ip ){
switch ( rand(1,3) ) {
case 1:
$this->setStatus( self::LOGIN_ACESS , $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_UNKNOW, $user, $ip );
$ret = FALSE;
break;
}
$this->notify();
return $ret;
}
/**
* 记录登录状态
*
* @param unknown_type $status
* @param unknown_type $user
* @param unknown_type $ip
*/
private function setStatus( $status, $user, $ip ){
$this->status = array( $status, $user, $ip );
}
/**
* 获得登录状态
*
* @return unknown
*/
function getStatus(){
return $this->status;
}
}
/*定义Observer*/
interface Observer{
function update( Observable $observable );
}
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__."\tsend mail to sysadmin\n";
}
}
}
/**
*记录log日志
*
*/
class GeneralLogger extends LoginObserver {
function doUpdate( Login $login ){
$status = $login->getStatus();
print __CALSS__.":\t add login data to log\n";
}
}
/**
* 登录ip匹配iplist
* 设置cookie
*
*/
class PartnershipTool extends LoginObserver {
function doUpdate( Login $login ){
$status = $login->getStatus();
print __CLASS__.":\t set cookie of ip match alist \n";
}
}
$login = new Login();
new SecurityMonitor( $login );
new GeneralLogger( $login );
new PartnershipTool( $login );

$login->handleLogin('snuser','s','s');


php可以通过内置的Spl(standard php library php标准类)提供观察者模式的原生支持。
SPl是一套可以帮助程序员处理很多面向对象的工具
其中观察者(obServer)由三个元素组成:SplObserver , SplSubject , SplObjectStrorage
其中SploOserver和SplSubject都是接口和上面所说的Observer 和 Observable接口完全相同
SplObjectStorage是一个工具类, 用于处理存储对象和删除对象。

下面就是改进后的示例代码
<?php
/**
* 使用php内部的对象工具,
* 完成观察者模式
* SplObserver
* SplSubject
* SplObjectStorage工具类用于存储对象和删除对象
* 实现用户登录 并且 记录下log 发送mail如果ip在匹配iplist设置cookie
*
*/

class Login implements SplSubject {
private $storage;
const LOGIN_USER_UNKNOW = 1;
const LOGIN_WRONG_PASS = 2;
const LOGIN_ACESS = 3;
private $status = array();
function __construct(){
$this->storage = new SplObjectStorage();
}
function attach( SplObserver $observer ){
$this->storage->attach( $observer );
}
function detach( SplObserver $observer ){
$this->storage->detach($observer);
}
function notify(){
foreach ( $this->storage as $obs ){
$obs->update( $this );
}
}
/**
* 登录启动器
* 记录登录状态
* return BOOLEAN
*
* */
function handleLogin( $user, $pass, $ip ){
switch ( rand(1,3) ) {
case 1:
$this->setStatus( self::LOGIN_ACESS , $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_UNKNOW, $user, $ip );
$ret = FALSE;
break;
}
$this->notify();
return $ret;
}
/**
* 记录登录状态
*
* @param unknown_type $status
* @param unknown_type $user
* @param unknown_type $ip
*/
private function setStatus( $status, $user, $ip ){
$this->status = array( $status, $user, $ip );
}
/**
* 获得登录状态
*
* @return unknown
*/
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 ){
$status = $login->getStatus();
if( $status[0] === LOGIN::LOGIN_WRONG_PASS ){
print __CLASS__."\tsend mail to sysadmin\n";
}
}
}
/**
*记录log日志
*
*/
class GeneralLogger extends LoginObserver {
function doUpdate( Login $login ){
$status = $login->getStatus();
print __CALSS__.":\t add login data to log\n";
}
}
/**
* 登录ip匹配iplist
* 设置cookie
*
*/
class PartnershipTool extends LoginObserver {
function doUpdate( Login $login ){
$status = $login->getStatus();
print __CLASS__.":\t set cookie of ip match alist \n";
}
}
$login = new Login();
new SecurityMonitor( $login );
new GeneralLogger( $login );
new PartnershipTool( $login );
$login->detach(new PartnershipTool( $login ));
$login->handleLogin('user','s','s');



[color=red]引用文章http://blog.csdn.net/swengineer/article/details/6268244[/color]

是一个观察者模式的案例。
/**
* 观察者模式应用场景实例
*
* 免责声明:本文只是以哈票网举例,示例中并未涉及哈票网任何业务代码,全部原创,如有雷同,纯属巧合。
*
* 场景描述:
* 哈票以购票为核心业务(此模式不限于该业务),但围绕购票会产生不同的其他逻辑,如:
* 1、购票后记录文本日志
* 2、购票后记录数据库日志
* 3、购票后发送短信
* 4、购票送抵扣卷、兑换卷、积分
* 5、其他各类活动等
*
* 传统解决方案:
* 在购票逻辑等类内部增加相关代码,完成各种逻辑。
*
* 存在问题:
* 1、一旦某个业务逻辑发生改变,如购票业务中增加其他业务逻辑,需要修改购票核心文件、甚至购票流程。
* 2、日积月累后,文件冗长,导致后续维护困难。
*
* 存在问题原因主要是程序的"紧密耦合",使用观察模式将目前的业务逻辑优化成"松耦合",达到易维护、易修改的目的,
* 同时也符合面向接口编程的思想。
*
* 观察者模式典型实现方式:
* 1、定义2个接口:观察者(通知)接口、被观察者(主题)接口
* 2、定义2个类,观察者对象实现观察者接口、主题类实现被观者接口
* 3、主题类注册自己需要通知的观察者
* 4、主题类某个业务逻辑发生时通知观察者对象,每个观察者执行自己的业务逻辑。
*
* 示例:如以下代码
*
*/

/**
* *
* 买票
* 记录购买信息
* 送优惠卷
* 短信日志记录
* 文本日志
*
*/
由于原文是使用JAVA来实现 , 下面我用phpSPL工具 来实现观察者模式 实现这个案例
/**
* 构建主题, 用于发送通知
*
*
* */
class buyTicket implements SplSubject {
private $ticket;
private $storage;
function __construct (){
$this->storage = new SplObjectStorage();
}
function attach( SplObserver $object ){
$this->storage->attach($object);
}
function detach( SplObserver $object ){
$this->storage->detach($object);
}
function notify(){
foreach ( $this->storage as $obs ){
$obs->update( $this );
}
}
/**
* 买票成功
* 发送通知记录日志
* 送折扣劵
*
* @return buyTicket
*/
function buyTicket(){
$this->ticket = 'NO.12, $100.';
$this->notify();
}
function getTicket(){
return $this->ticket;
}
}
/**
* 接收通知的观察者
* 判断通知来源, 并且相应观察者执行相应的操作
*
*/
abstract class ticketObject implements SplObserver {
private $buyTicket;
function __construct( buyTicket $buyTicket ){
$this->buyTicket = $buyTicket;
$buyTicket->attach( $this );
}
function update( SplSubject $subject ) {
if( $subject === $this->buyTicket ){
$this->doUpdate( $subject );
}
}
abstract function doUpdate( SplSubject $buyTicket );
}
/**
*
* 日志观察者接到通知记录日志
*
*/
class ticketLogger extends ticketObject {
function doUpdate( SplSubject $buyTicket ){
print __CLASS__.' 日志计入 买票 '.$buyTicket->getTicket()."\n";
}

}
/**
*
* 折扣劵观察者 接到通知发送折扣劵
*
*/
class ticketDid extends ticketObject {
function doUpdate( SplSubject $buyTicket ){
print __CLASS__."\t 送10元折扣卷一张".$buyTicket->getTicket();
}
}
$ticket = new buyTicket();
new ticketLogger( $ticket );
new ticketDid( $ticket );
$ticket->buyTicket();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值