专栏首页吉林乌拉设计模式之观察者模式

设计模式之观察者模式

今天我继续和大家分享一下设计模式中的知识,今天我们来看一下观察者模式。观察者模式也可以叫发布订阅模式,在实际的场景中有很多时候会遇到这种设计模式。在现实的生活中可以将这种模式理解为报纸订阅服务。也就是说,如果用户订阅了某个报社的报纸,那么报社在收到这个订阅请求后,就会每天把最新的报纸送到用户的手中,如果某一天用户不想继续看这家报社的报纸了,那么就可以取消这个订阅,那么这时报社又收到这个用户取消订阅的请求,然后把这个用户从以后的送报纸用户的名单中删除掉。所以第二天在给其他用户送报纸的时候,就不会继续给这个用户送了。通过上面这个小的例子使我们知道所谓观察者也就是上述例子中的用户,那么这个用户在观察什么呢?答案可显而知,也就是观察订阅这家报社的报纸有没有最新的,如果有最新的报纸,那么报社就会自动将新的报纸,送到自己的手中。那么报纸如果没有最新的呢,也就是没有更新呢?例如在法定假日期间,(并不是所有的报纸都是按天发版的,还有一些报纸法定假日停刊),那么这时用户就不会收到新的报纸了。

上面我举了报纸订阅的服务来简单说明了观察者模式。那么接下来我们将按照软件开发的角度,来分析一下观察者模式的具体使用。我们前面提到过了,观察者模式的例子有很多,我们下面将以用户在网上买东西,也就是用户下单为例来详细了解一下观察者模式的使用。

大家知道,在电商网站中,用户在网上成功买完东西付款成功后,系统都会为该用户创建一个订单来记录用户所购买的所有商品,实际上当用户购买失败时,系统也会创建订单,只不过该订单用户支付状态为失败而已。这里我们暂时只考虑支付成功的情况,也就是默认用户如果下单了,就支付成功。虽然用户支付成功了,但对于系统来说这个流程还没有完毕,这刚好只是个开始,因为当用户下单成功后我们系统在后续的处理中会涉及到很多个系统的调用。例如:物流系统、商品系统、积分系统等等。也就是说当用户下单成功后,会调用物流系统、商品系统、积分系统等这些系统来分别处理相应的逻辑。只要系统检测到了订单发生了变化(暂时我们只考虑成功的情况),其它的系统也跟着发生变化。在这一点上和我们上述报纸订阅服务是一个意思。只不过不同的之处就是把用户换成了不同的系统而已,而不同的系统要观察的就是订单是否变化。下面我们按照这样的思路把上述的业务用代码表现出来,具体的代码如下。

我们看输出实现了我们想要的结果,也就是当订单发生更新时,其他3个系统都会收到信息。但我们在之前的文章中提到过,我们在设计系统时,不要针对实现编程,要针对接口编程,这样程序比较方便扩展。按照我们上述的代码,如果我们要添加新的系统,例如卡卷系统 ,那么这时我们就要修改曾经已经编写好的代码,也就是OrderSuccess接口,那这就违背了设计模式的基本原则了。显然上述的代码,虽然可以实现需求,但是却不是最好的,因为不方便扩展。那么怎么办?我们分析需求知道这显然是一个一对多的关系,当订单更新时,其他和它相关的系统都需要接到通知然后更新,类似报纸订阅是一样的,只要报纸发生变化,那么订阅该报纸的人都能知道。其实,这就是典型的观察者模式。下面我们先看一下观察者模式的定义。

观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

我们在说的简单点比如对一个有状态的对象,我们称之为主题对象,然后我们有一堆和主题对象依赖的对象,我们叫它观察者对象。这样当主题对象更新时,观察者对象会自动收到通知并更新。

按照我们上面的代码怎么把他们修改为观察者模式呢?我们按之前学到的知识应该对接口编程,而不是对实现编程。所以我们应该抽取出两个接口一个是主题接口,一个是观察者接口。这样主题只知道了观察者都实现了观察者接口,而主题不需要知道观察者具体的类是谁,这样在任何时候我们都可以随时增加新的观察者,只要实现观察者接口就可以了。而主题并不做任何的修改,因为主题对象唯一依赖的东西是一个实现了观察者接口的对象列表,所以我们可以随时添加任意的观察者,而主题对象并不需要做任何的更新,这就遵循了设置模式的原则,将对象中可能变化的部分提取出来,这样当其他对象变化时,该对象不需要做任何的更改。这里我们还有一个重要的设置模式原则,也就是为交互对象之间的松耦合设计而努力。在说的直白点就是我们在设计系统时应该将对象与对象之间的耦合度设计的尽量低,耦合度越低,对象与对象的依赖关系也就越低,这样也就方便我们更好的扩展。

那我们应该怎么将上述的代码修改为观察者模式呢?通过以前的知识我们知道应该对接口编程,而不是对实现编程,因为这样我们比较方便扩展。所以我们应该将上述代码中涉及到的物流系统、商品系统、积分系统抽象出一个公共的接口,同理我们也将订单抽象出一个接口,这样的好处是,当创建新的子类时,对接口的编程代码是不需要变化的,这就遵循了我们上述提到过的松耦合了。下面我们将上述代码修改为真正的观察者模式,具体代码如下:

这样我们就将上述的代码修改为真正的观察者模式的代码,这样的好处就是非常方便我们的扩展,我们在新添加新的系统时,而并不需要修改曾经已经开发好的代码,也就是订单中的已有的代码,这样就真正做到了可扩展了。下面我们将新增一个卡卷系统,来证明我们上述所说的可扩展性。

快看,我们成功的将新的卡卷系统添加到了这个观察者了,并且它成功收到了订单变更的通知,并且我们并没有修改任何有关订单的代码,这就是我们上面所说的低耦合,这也就是观察者模式的好处。

到这里,我们已经将观察者模式都介绍完了,本应该到这里就结束了,但这个观察者模式有点特别,Java为了我们更方便的使用观察者模式,所以在Java中直接内置的支持观察者模式,也就是我们自己并不需要创建主题和观察者了,因为Java中直接就提供了这两个接口(确切的说是一个接口和一个类)。下面我们将上述的代码,用Java中内置的观察者模式来实现。

下面为具体的代码:

我们看使用Java内置的观察者和我们自定义的观察者模式的效果是一样的,但代码却大大的减少了,因为大部分的代码都已经被内置的实现了。虽然这样有很大的好处,但有一点不太方便,可能你们也发现了,也就是Observable是一个类,而不是一个接口,如果我们要想使用Java内置的观察者模式,如果主题已经继承了其他的父类,那我们就不能使用Java内置的观察者模式了,因为在Java中并不支持多重继承,这也就是Java内置的观察者模式的弊端。

本文分享自微信公众号 - 吉林乌拉(jilinwulacom),作者:吉林乌拉

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-20

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 自动创建代理-BeanNameAutoProxyCreator

    在其它的文章中我们基本都是采用ProxyFactoryBean类来创建代理类的,但在使用此类时,我们通常要设置很多属性不方便我们使用。在spring中我们还可以...

    吉林乌拉
  • 公平锁与非公平锁

    我们看输出线程的运行顺序和线程获取锁的顺序是一致的。这就是公平锁的特征,先到先得。下面我们看一下非公平锁。

    吉林乌拉
  • 垃圾收集算法

    垃圾收集器是Java虚拟机中自带的功能,它的目的是帮助我们管理内存,正是因为有它的存在所以,我们在开发时,基本不用考虑内存溢出等问题。基本不用考虑不代表,一定不...

    吉林乌拉
  • 一起学设计模式 - 观察者模式

    观察者模式是一种使用率极高的模式,用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。在观察者模式中,发生改变的...

    battcn
  • 观察者模式(设计模式)

    观察者模式其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。可以想象成消息中间件在系统中的作用。SpringBoot...

    WindSun
  • 设计模式----观察者模式

    SuperHeroes
  • Java设计模式学习记录-观察者模式

    观察者模式也是对象行为模式的一种,又叫做发表-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、 咱们目前用的最多的就是各...

    纪莫
  • ThoughtWorks——结对编程

    面试一般都是纸上谈兵,尤其是设计模式这种需要“付诸实践”的面试题。面试前先给面试者布置“家庭作业”,然后Thoughtworks会派工程师和面试者进行结对编程,...

    Anymarvel
  • 观察者模式 Observer 发布订阅模式 源 监听 行为型 设计模式(二十三)

    定义对象一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖他的对象都得到通知并自动更新。

    noteless
  • Rxjava2-小白入门(一)

    最近在学习Rxjava2,虽然在实际的项目中使用也看了很多的文章和文档,学会的了如何使用但是忘记的很快,也没有很好的总结,在学习的时做的笔记过了一段时间发现自己...

    g小志

扫码关注云+社区

领取腾讯云代金券