设计模式16之观察者模式

背景

观察者模式你肯定知道并且用过,如果你没听过观察者模式这几个词,那发布-订阅模型你肯定知道。我们在使用Kafka等消息中间件时,就用到了发布-订阅模式进行数据的生产消费。你可以将发布-订阅模式理解为观察者模式。

如下代码:

kafka发布消息:

 ListenableFuture future = kafkaTemplate.send(topic, jsonString);

消费者订阅消息:

@KafkaListener(topics = "${spring.kafka.topic}")
 public void listen(ConsumerRecord<?, ?> record) {
        log.info("topic={}, offset={}, message={}", record.topic(), record.offset(), record.value());
 }

上面就是kafka发布-订阅的使用方法。

除了消息中间件的发布-订阅,zookeeper的watch机制也使用到了观察者模式。各位可以思考下,你在什么情况下会使用观察者模式呢?

什么是观察者模式

在现实生活中,许多对象都不是独立存在的,其中一个对象的改变往往会导致其它对象的改变。比如:到了下班时间你会下班回家,路上遇到红灯你会停下来,股市行情好了你会追加投资。

如果你在开发中要描述上述的关联关系,就可以使用观察者模式。

Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically.(定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。)

观察者模式的主要由4个要素组成:

  • 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。

  • 具体主题(Concrete  Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。

  • 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。

  • 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

结构图如下:

观察者模式

代码实现

Subject

Observer

ConcreteSubject

ConcreteObserver

测试代码如下:

@Test
public void test() {
    Subject subject=new ConcreteSubject();
    Observer obs1=new ConcreteObserver1();
    Observer obs2=new ConcreteObserver2();
    subject.add(obs1);
    subject.add(obs2);
    subject.notifyObserver();
}

测试结果如下:

具体目标发生改变...
--------------
具体观察者1作出反应!
具体观察者2作出反应!

关于观察者模式的思考

我们什么情况下可以使用观察者模式呢?

如果对象之间存在一对多关系,一个对象的状态发生改变会影响其他对象,我们就能使用观察者模式。我举个例子,如果某个商品出现质量问题。我们需要对已经购买该商品的订单冻结,那么我们就可以使用观察者模式。我们对该商品执行冻结命令,冻结该商品的同时,所有包含该商品的订单都会被通知并冻结。

我们再思考一下,在另一个场景中。用户下单后,需要送积分,生成物流信息,短信通知,微信通知,是不是可以使用观察者模式呢?关于这个问题我之前还写了一篇文章探讨使用观察者模式的好处,有兴趣的可以看看。

开发实战-我用Spring的事件监听机制实现了模块的解耦

不知你发现了没有,观察者和被观察者之间的耦合度很低。这样观察者和被观察者很容易扩展。

观察者模式很容易实现一条触发链。什么是触发链呢?比如早上闹钟把你闹醒,你就起床,你肚子饿了,你就会去吃早餐,快到上班时间了,你就会开车去上班,上班时间到了,你就打开电脑开始摸鱼。这一连串的的触发机制就形成了一个触发链。

观察者模式需要考虑一下开发效率和运行效率问题,一个被观察者,多个观察者,开发和调试就会比较复杂,而且在Java中消息的通知默认是顺序执行,一个观察者卡壳,会影响整体的执行效率。在这种情况下,一般考虑采用异步的方式。

往期推荐

扫码二维码,获取更多精彩。或微信搜Lvshen_9,可后台回复获取资料

  1. 回复"java" 获取java电子书;

  2. 回复"python"获取python电子书;

  3. 回复"算法"获取算法电子书;

  4. 回复"大数据"获取大数据电子书;

  5. 回复"spring"获取SpringBoot的学习视频。

  6. 回复"面试"获取一线大厂面试资料

  7. 回复"进阶之路"获取Java进阶之路的思维导图

  8. 回复"手册"获取阿里巴巴Java开发手册(嵩山终极版)

  9. 回复"总结"获取Java后端面试经验总结PDF版

  10. 回复"Redis"获取Redis命令手册,和Redis专项面试习题(PDF)

  11. 回复"并发导图"获取Java并发编程思维导图(xmind终极版)

另:点击【我的福利】有更多惊喜哦。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值