隔墙有耳的观察者模式(ObserverPatern)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了隔墙有耳的观察者模式(ObserverPatern),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含7738字,纯文字阅读大概需要12分钟。
内容图文
![隔墙有耳的观察者模式(ObserverPatern)](/upload/InfoBanner/zyjiaocheng/151/43c9ead35f884f31ad89f1f2abba0fea.jpg)
很简单的模式,实现代码:
Php代码
<?php interface Observable{ function attach( Observer $observer ); function detach( Observer $observer ); function notify(); } class login implements Observable{ const LOGIN_USER_UNKNOW = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_ACCESS = 3; private $status = array(); private $observers = array(); public function setStatus( $status, $user, $ip ) { $this->status = array( $status, $user, $ip ); } public function getStatus() { return $this->status; } public function handleLogin( $user, $pass, $ip ) { switch ( mt_rand( 1, 3 ) ) { case 1: $this->setStatus( self::LOGIN_USER_UNKNOW, $user, $ip ); $ret = false; break; case 2: $this->setStatus( self::LOGIN_WRONG_PASS, $user, $ip ); $ret = false; break; case 3: $this->setStatus( self::LOGIN_ACCESS, $user, $ip ); $ret = true; break; } $this->notify(); return $ret; } public function attach( Observer $observer ) { $this->observers[] = $observer; } public function detach( Observer $observer ) { $newObservers = array(); foreach ( $this->observers as $obs ) { if ( $obs !== $observer ) $newObservers[] = $obs; } $this->observers = $newObservers; } public function notify() { foreach ( $this->observers as $obs ) { $obs->update( $this ); } } } interface Observer{ function update( Observable $observable ); } class SecurityMonitor implements Observer{ function update( Observable $observable ) { $status = $observable->getStatus(); if($status[0] == Login::LOGIN_WRONG_PASS){ echo __CLASS__.":".$status[1]."于".$status[2]."登录失败"; } } } $login = new Login(); $login->attach(new SecurityMonitor()); $login->handleLogin('XXX','XXX','127.0.0.1'); ?>
出错时的运行结果:
SecurityMonitor:XXX于127.0.0.1登录失败[Finished in 0.1s]
代码中可以看到login对象主动添加SecurityMonitor对象观察。这样要调用Login::getStatus(),SecurityMonitor类就必须了解更多信息。虽然调用发生于一个ObServable对象上,但无法保证对象也是一个Login对象。为解决这个问题,有一个办法:断续保持ObServable接口的通用性,由ObServer类负责保证它们的主体是正确的类型。它们甚至能将自己添加到主体上。类图如下:
实现代码如下:
Php代码
<?php interface Observable{ function attach( Observer $observer ); function detach( Observer $observer ); function notify(); } class login implements Observable{ const LOGIN_USER_UNKNOW = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_ACCESS = 3; private $status = array(); private $observers = array(); public function setStatus( $status, $user, $ip ) { $this->status = array( $status, $user, $ip ); } public function getStatus() { return $this->status; } public function handleLogin( $user, $pass, $ip ) { switch ( mt_rand( 1, 3 ) ) { case 1: $this->setStatus( self::LOGIN_USER_UNKNOW, $user, $ip ); $ret = false; break; case 2: $this->setStatus( self::LOGIN_WRONG_PASS, $user, $ip ); $ret = false; break; case 3: $this->setStatus( self::LOGIN_ACCESS, $user, $ip ); $ret = true; break; } $this->notify(); return $ret; } public function attach( Observer $observer ) { $this->observers[] = $observer; } public function detach( Observer $observer ) { $newObservers = array(); foreach ( $this->observers as $obs ) { if ( $obs !== $observer ) $newObservers[] = $obs; } $this->observers = $newObservers; } public function notify() { foreach ( $this->observers as $obs ) { $obs->update( $this ); } } } interface Observer{ function update( Observable $observable ); } //以上代码和上例是一样的 abstract class LoginObserver implements Observer{ private $login; public function __construct( Login $login ) { $this->login = $login; $login->attach( $this ); } public function update( Observable $observable ) { if ( $this->login === $observable ) $this->doUpdate( $observable ); } abstract function doUpdate( Login $login ); } class SecurityMonitor extends LoginObserver{ public function doUpdate( Login $login ) { $status = $login->getStatus(); if ( $status[0] == Login::LOGIN_WRONG_PASS ) echo __CLASS__.":".$status[1]."于".$status[2]."登录失败"; } } $login = new Login(); new SecurityMonitor($login);//<strong>此外login对象是被动被观察的</strong> $login->handleLogin( 'XXX', 'XXX', '127.0.0.1' ); ?>
运行结果与上例子相同
在php5后,内置的SPL扩展提供了对观察者模式的原生支持。将上例子通过SPL改进后:
Php代码
<?php class login implements SplSubject{ const LOGIN_USER_UNKNOW = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_ACCESS = 3; private $status = array(); // private $observers = array(); private $storage; public function __construct() { $this->storage = new SplObjectStorage(); } public function setStatus( $status, $user, $ip ) { $this->status = array( $status, $user, $ip ); } public function getStatus() { return $this->status; } public function handleLogin( $user, $pass, $ip ) { switch ( mt_rand( 1, 3 ) ) { case 1: $this->setStatus( self::LOGIN_USER_UNKNOW, $user, $ip ); $ret = false; break; case 2: $this->setStatus( self::LOGIN_WRONG_PASS, $user, $ip ); $ret = false; break; case 3: $this->setStatus( self::LOGIN_ACCESS, $user, $ip ); $ret = true; break; } $this->notify(); return $ret; } public function attach( SplObserver $observer ) { $this->storage->attach( $observer ); } public function detach( SplObserver $observer ) { $this->storage->detach( $observer ); } public function notify() { foreach ( $this->storage as $obs ) { $obs->update( $this ); } } } abstract class LoginObserver implements SplObserver{ private $login; public function __construct( Login $login ) { $this->login = $login; $login->attach( $this ); } public function update( SplSubject $subject ) { if ( $this->login === $subject ) $this->doUpdate( $subject ); } abstract function doUpdate( Login $login ); } class SecurityMonitor extends LoginObserver{ public function doUpdate( Login $login ) { $status = $login->getStatus(); if ( $status[0] == Login::LOGIN_WRONG_PASS ) echo __CLASS__.":".$status[1]."于".$status[2]."登录失败"; } } $login = new Login(); new SecurityMonitor( $login ); $login->handleLogin( 'XXX', 'XXX', '127.0.0.1' ); ?>
代码都写完了,还是要懂点理论的。
观察者模式的定义
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。观察者模式由四种角色构成:
1、Subject被观察者
定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责,管理观察者并通过观察者。
2、Observer观察者
观察者接收到消息后,即进行update操作,对接收到的信息进行处理。
3、ConcreteSubject具体的被观察者
定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。
4、ConcreteObserver具体的观察者
每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。
观察者模式的优点
1、观察者和被观察者之间是抽象耦合
如此设计,则不管是增加观察者还是被观察者都非常容易扩展,而且在java、php中都已经实现的抽象层级的定义,在系统扩展方面更是得心应手。
2、建立一套触发机制
根据单一职责原则,每个类的职责是单一的,那么怎么把各个单一的职责串联成真实世界的复杂的逻辑关系呢?观察者模式可以完美地实现这里的链条形式
观察者模式的缺点
观察者模式需要考虑一下开发效率和运行效率的问题,一个被观察者,多个观察者,开发和调试就会比较复杂,而且在php中消息的通知是顺序执行,一个观察者卡壳,会影响整体的执行效率。在这种情况下,一般多考虑异步的方式。多级触发时的效率更是让人担忧,设计时注意。
观察者模式的使用场景
1、关联行为场景。需要注意的是,关系行为是可拆分的,而不是“组合”关系
2、事件多级触发场景
3、跨系统的消息交换场景,如消息队列的处理机制
内容总结
以上是互联网集市为您收集整理的隔墙有耳的观察者模式(ObserverPatern)全部内容,希望文章能够帮你解决隔墙有耳的观察者模式(ObserverPatern)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。