PHP设计模式之观察者模式实例


Posted in PHP onFebruary 22, 2016

首先了解观察者模式的概念:一个对象通过添加一个方法(该方法允许另一个对象,即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。观察者模式是一种事件系统,意味着这一模式允许某个类观察另一个类的状态,当被观察的类状态发生改变的时候,观察类可以收到通知并且做出相应的动作;观察者模式为您提供了避免组件之间紧密耦。

UML结构图:

PHP设计模式之观察者模式实例

观察者模式解决的问题

在我们的开发过程中,应该都或多或少的碰到过改动其中一部分代码会引起其他一连串改变的问题,显然想要完全避免这种情况不太可能,但我们也应答尽量减少对其他组件的依赖,而观察者模式就是为了解决这个问题。

举个例子来说,我们有一个帖子对象,代码如下:

class Post
{
protected $_userid = null;
protected $_ip = null;
protected $_content = null;
function __construct()
{
// ...
}
// 发帖方法
public function addPost()
{
// ... 发帖逻辑
}
}

在上面是一个普通的帖子对象,随着发帖量和访问量越来越大,运营们开始不干了,公司也经常会接到投诉电话,说我们的网站有许多敏感内容和垃圾广告,因此我们需要做内容审核:首先是对用户的审核,一些黑名单用户应该被禁止发帖;二是对IP的审核;三是对内容敏感词的审核。因此我们的代码就成了如下的样子:

class Post
{
protected $_userid = null;
protected $_ip = null;
protected $_content = null;
function __construct()
{
}
public function addPost()
{
if (!Postscan::checkUserid($tihs->_userid)) {
return false;
}
if (!Postscan::ipUserid($tihs->_ip)) {
return false;
}
if (!Postscan::checkContent($tihs->_content)) {
return false;
}
// ... 
}
}

随着需要审核的字段越来越多,addPost方法变得越来越长,发布对象被也只能紧紧的被嵌入到该系统中。

观察者模式的实现

观察者模式的核心是把观察者从主体中分离开来,当主体知道事件发生时,观察需要被通知到,同时我们也不想把主体和观察者之间的关系写死,于是我们来修改下我们上面的代码:

//主体必须实现的接口
interface Observable {
public function attach(Observer $observer);
public function detach(Observer $observer);
public function notify();
}
//观察者必须实现的接口
interface Observer {
public function do(Observable $subject);
}
class Post implements Observable
{
protected $_userid = null;
protected $_ip = null;
protected $_content = null;
protected $_observerlist = array();
function __construct()
{
}
public function attach(Observer $observer)
{
$this->_observerlist[] = $observer;
}
public function detach(Observer $observer)
{
foreach ($this->_observerlist as $key => $value) {
if ($observer === $value) {
unset($this->_observerlist[$key])
}
}
}
public function notify()
{
foreach ($this->_observerlist as $value) {
if (!$value->do($this)) {
return false;
}
}
return true;
}
public function addPost()
{
if (!$this->notify()) {
return false;
}
// ... 
}
}

通过上面的代码,我们可以再很容易的加入审核规则。

SPL代码

观察者模式是一个很常见和常用的设计模式,以至于SPL扩展已经为我们封装好了对应的类和方法,下面的代码是根据SPL提供的3个元素:SplObserver,SplSubject,SplObjectStorage来实现的代码

class Post implements SplSubject
{
protected $_userid = null;
protected $_ip = null;
protected $_content = null;
protected $_storage = new SplObjectStorage();
function __construct()
{
}
public function attach(SplObject $observer)
{
$this->_storage->attach($observer);
}
public function detach(SplObject $observer)
{
$this->_storage->detach($observer);
}
public function notify()
{
foreach ($this->_storage as $value) {
if (!$value->update($this)) {
return false;
}
}
return true;
}
public function addPost()
{
if (!$this->notify()) {
return false;
}
// ... 
}
}

很简单吧,最重要的是理解,在这个例子中,我们把一些审核的方法从帖子类中剥离了开来,而且该帖子对象也可以用来作为其他的发布类型。

以上内容实现是小编给大家介绍的PHP设计模式之观察者模式,希望对大家有所帮助!

PHP 相关文章推荐
基于mysql的论坛(4)
Oct 09 PHP
php empty函数 使用说明
Aug 10 PHP
php遍历目录viewDir函数
Dec 15 PHP
php 删除记录同时删除图片文件的实现代码
May 12 PHP
php中防止伪造跨站请求的小招式
Sep 02 PHP
让Json更懂中文(JSON_UNESCAPED_UNICODE)
Oct 27 PHP
php中flush()、ob_flush()、ob_end_flush()的区别介绍
Feb 17 PHP
使用php+apc实现上传进度条且在IE7下不显示的问题解决方法
Apr 25 PHP
Windows下的PHP安装pear教程
Oct 24 PHP
Web程序工作原理详解
Dec 25 PHP
PHP开发中解决并发问题的几种实现方法分析
Nov 13 PHP
PHP rmdir()函数的用法总结
Jul 02 PHP
PHP编写RESTful接口的方法
Feb 21 #PHP
PHP常见漏洞攻击分析
Feb 21 #PHP
php采集神器cURL使用方法详解
Feb 19 #PHP
PHP 使用 Imagick 裁切/生成缩略图/添加水印自动检测和处理 GIF
Feb 19 #PHP
PHP利用imagick生成组合缩略图
Feb 19 #PHP
对比分析php中Cookie与Session的异同
Feb 19 #PHP
php强大的时间转换函数strtotime
Feb 18 #PHP
You might like
与空气斗智斗勇的经典《Overlord》,传说中的“无稽之谈”
2020/04/09 日漫
php循环输出数据库内容的代码
2008/05/24 PHP
使用PHP生成二维码的两种方法(带logo图像)
2014/03/14 PHP
php中smarty变量修饰用法实例分析
2015/06/11 PHP
PHP如何实现Unicode和Utf-8编码相互转换
2015/07/29 PHP
在WordPress中安装使用视频播放器插件Hana Flv Player
2016/01/04 PHP
PHP读取文本文件并逐行输出该行使用最多的字符与对应次数的方法
2016/11/25 PHP
PHP执行shell脚本运行程序不产生core文件的方法
2016/12/28 PHP
PHP析构函数destruct与垃圾回收机制的讲解
2019/03/22 PHP
详解JavaScript数组的操作大全
2015/10/19 Javascript
jQuery Mobile框架中的表单组件基础使用教程
2016/05/17 Javascript
详解js的六大数据类型
2016/12/27 Javascript
JavaScript与JQUERY获取元素的宽、高和位置
2017/02/26 Javascript
用angular实现多选按钮的全选与反选实例代码
2017/05/23 Javascript
jQuery实现滚动到底部时自动加载更多的方法示例
2018/02/18 jQuery
Vue中控制v-for循环次数的实现方法
2018/09/26 Javascript
vue里input根据value改变背景色的实例
2018/09/29 Javascript
原生JS实现萤火虫效果
2020/03/07 Javascript
javascript实现京东登录显示隐藏密码
2020/08/02 Javascript
详解Django通用视图中的函数包装
2015/07/21 Python
简单了解Python下用于监视文件系统的pyinotify包
2015/11/13 Python
Python自动化部署工具Fabric的简单上手指南
2016/04/19 Python
python爬取哈尔滨天气信息
2018/07/14 Python
Python 文本文件内容批量抽取实例
2018/12/10 Python
python消费kafka数据批量插入到es的方法
2018/12/27 Python
pymongo中聚合查询的使用方法
2019/03/22 Python
pygame实现贪吃蛇游戏(下)
2019/10/29 Python
python GUI库图形界面开发之PyQt5滑块条控件QSlider详细使用方法与实例
2020/02/28 Python
python访问hdfs的操作
2020/06/06 Python
python爬虫scrapy框架的梨视频案例解析
2021/02/20 Python
python 对xml解析的示例
2021/02/27 Python
金融与证券专业求职信
2014/06/22 职场文书
英雄儿女观后感
2015/06/09 职场文书
食堂管理制度范本
2015/08/04 职场文书
教师培训学习心得体会
2016/01/21 职场文书
Windows Server 修改远程桌面端口的实现
2022/06/25 Servers