设计模式专题(十)——观察者模式

设计模式专题(十)——观察者模式

(原创内容,转载请注明来源,谢谢)

一、概述

观察者模式(Observer),又称做发布-订阅模式(Publish/Subscribe),定义了一种一对多的依赖关系,让多个观察者对象监听同一个主题对象。当主题对象状态变化时,会通知所有观察者对象,让他们能够自动更新自己。

该模式下,将发布者和消费者都设定一个抽象,发布者发布消息,消费者收到消息后会自动进行后续的操作,不同的消费者收到同一个消息,可以有不同的操作。

但是,这样会使得发布者和订阅者之间的耦合度过高,且会使得消费者之间被绑定在一起。通常情况下,消费者是一些毫不相关的类,如用户完成支付后,同时给用户发送短信提醒、微信推送、站内信,且还需要给发货系统发送一个新的订单,给仓库发送一个提货信息,本系统内部也需要记录操作日志、数据入库等。这些操作完全不一样,无法使用一个统一的方式来实现。

在C#中可以用委托配合发布订阅的方式作为解决方案,在PHP中可以自行实现委托。

二、类图

此类图为普通的观察者模式类图,在上文中说的改进版的类图,解除消费者之间的关系,因此撤掉上图的Observer类,使每个消费者各自独立。

三、业务场景

1、场景分析

现实现上述用户支付完成后的场景,考虑到多个用户在短时间内都完成支付,因此还需要加上消息队列。

1)抽象类Subject,定义发布者需要执行的方法。

2)发布类ConcreteSubject,具体实现发布。

3)Observer1、Observer2… 若干消费者,实现各自的功能。

2、伪代码实现

1)抽象发布类

抽象发布类主要是将动态添加发布方法这一操作提取出来,其他的具体发布类都可以直接使用此方法。

         abstractclass Subject{
         protected $events;
         public function__construct(){
                   $this->events= array();
         }
         //定义不同的发布方式
         public functionsend(){}
         //添加类型:类的实例-》方法名-》参数
         public functionaddEvents($obj, $func, $args){
                   array_push($events,array($obj, $func, $args));
         }
}

2)具体发布类

具体发布类将发布的信息,以类作为key,存在消息队列中(如redis)。

class ConcreteSubject extends Subject{
         public functionsend(){
                            foreach($this->events as$event){
                            //redis->lpush(get_class($event[0]),array($event[1], $event[2]))
                   }
         }
}

3)具体消费者

具体消费者通过redis去不断的取各自的服务,在收到请求后立即执行各自的服务。

四、评价

观察者模式,通过结合消息队列,使得发布者和消费者之间完全隔离开。

对某个事件的触发,由发布者进行执行,并且由发布者判断要发送给哪些消费者。

对事件的处理,由消费者在自己的消息队列中取内容进行处理,当队列为空时处于等待状态(或者几分钟处理一次,可以根据具体情况设置处理策略),当队列收到来自发布者发布的内容后。

例如用户支付后,短信模块(消费者)收到支付模块(发布者)的发送短信告知用户支付成功的消息,短信模块再去做自身的处理。

这样使得类之间耦合度降低,且当发生故障时,也很容易排查故障发生的模块。例如短信没有发送成功,支付模块查看是否有发送消息给短信模块,并且查看发送的内容是否符合规范;短信模块判断是否因为修改逻辑,或其他bug,导致短信无法发送。

——written by linhxx 2017.08.02

相关阅读:

设计模式专题(九) ——外观模式

设计模式专题(八) ——模板方法模式

设计模式专题(七)——建造者模式

设计模式专题(六)——原型模式

设计模式专题(五)——工厂方法模式

设计模式专题(四)——代理模式

设计模式专题(三)——装饰模式

设计模式专题(二)——策略模式

设计模式专题(一)——面向对象的设计原则

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-08-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏PHP技术

PHP开发人员常犯的10个MysqL错误

对于大多数web应用来说,数据库都是一个十分基础性的部分。如果你在使用PHP,那么你很可能也在使用MySQL—LAMP系列中举足轻重的一员。 对于很多新手们来说...

2684
来自专栏韩伟的专栏

状态模式:一个Epoll边缘触发的代理服务器设计

设计模式是一门热门的知识,但是何时应该用哪个,却往往不容易掌握,本文以一个Socks5代理服务器的设计为例,介绍状态模式的实践用法。 软件的功能介绍 提供Soc...

3647
来自专栏IT技术精选文摘

使用Lagom和Java构建反应式微服务系统

介绍 Lagom是一个帮助您构建反应式微服务的框架。 大多数微服务框架着重于帮助您构建脆弱的单实例微服务,根据定义,这些微服务不具可扩展性或不具有弹性。 L...

2195
来自专栏微信终端开发团队的专栏

微信终端跨平台组件 mars 系列(一):高性能日志模块xlog

mars 是微信官方的终端基础组件,是一个使用 C++ 编写的业务性无关,平台性无关的基础组件。本文章是 mars 系列的第一篇:高性能跨平台日志模块。

2360
来自专栏凉城

[教程]ping还有高级用法你知道吗?

1425
来自专栏乐沙弥的世界

Oracle RAC OCR 的备份与恢复

        Oracle Clusterware把整个集群的配置信息放在共享存储上,这些信息包括了集群节点的列表、集群数据库实例到节点的映射以及CRS应用...

482
来自专栏吴伟祥

Linux Partition scheme 分区方案(一)

根分区包含Linux系统所有的目录。如果在安装系统时只分配了/分区,那么上面的/boot、/usr和/var将都包含在根分区中,也就是这些分区将占用根分区的空间...

902
来自专栏Youngxj

[教程]ping还有高级用法你知道吗?

944
来自专栏JMCui

Node.js入门以及第一个helloworld程序.

1、概念:简单的说 Node.js 就是运行在服务端的 JavaScript。学之前需要明白Node.js是无法挑战jsp、php或者asp这种老牌网站的地位的...

2583
来自专栏SDNLAB

【连载-5】数据中心网络虚拟化 网关及服务接入

网络虚拟化网关技术 虚拟网络中的虚拟机与外部网络通信的需求催生了网络虚拟化中网关(Gateway)技术的出现。现有虚拟化平台网关产品有:IBM SDN VE G...

3168

扫描关注云+社区