Java里观察者模式(订阅发布模式)

  • 创建主题(Subject)接口
  • 创建订阅者(Observer)接口
  • 实现主题
  • 实现观察者
  • 测试
  • 总结

在公司开发项目,如果碰到一些在特定条件下触发某些逻辑操作的功能的实现基本上都是用的定时器

比如用户注册完后,发送邮件,为了防止邮件发送失败或者发送邮件比较耗时,一般也都是通过定时器去扫库里注册没有发邮件的用户数据

再比如一个订单,在改变状态后,要归档,这也是通过定时器来实现的,扫描订单的数据,通过判断状态来做相对应的处理

但这样处理的话,定时器就会越来越多,总觉得不太好

然后,从一些资讯网站上的订阅功能想到了是否可以使用java里的观察者模式来解决这个问题,比如定单的状态改变了,这是一个主题,直接通知订阅这个主题的实现类来处理这个订单,这样不是更方便吗,于是从观察者模式入手,折腾了一下

创建主题(Subject)接口

定义主题的接口

package co.yiiu;

/**
 * Created by tomoya at 2019/4/8
 */
public interface Subject {

  // 设置主题内容
  void setContent(String content);

  // 获取主题内容
  String getContent();

  // 添加订阅者
  void attach(Observer observer);

  // 删除订阅者
  void detach(Observer observer);

  // 发布消息
  void publish();
}

创建订阅者(Observer)接口

package co.yiiu;

/**
 * Created by tomoya at 2019/4/8
 */
public interface Observer {

  // 订阅主题
  void subscribe(Subject subject);

  // 取消订阅
  void unsubscribe(Subject subject);

  // 处理订阅的消息
  void update(Subject subject);
}

原链文接:https://tomoya92.github.io/2019/04/08/java-subscribe-publish/

实现主题

我这里实现了两个主题

  • NewsSubject 新闻主题,订阅了这个主题的观察者可以获取这个主题更新的新闻内容
  • WeatherSubject 天气主题,订阅了这个主题的观察者可以获取这个主题发布的天气情况

具体代码如下

package co.yiiu;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by tomoya at 2019/4/8
 */
public class NewsSubject implements Subject {

  private String content;
  private List<Observer> observers = new ArrayList<>();

  @Override
  public String getContent() {
    return content;
  }

  @Override
  public void setContent(String content) {
    this.content = content;
  }

  // 添加观察者
  @Override
  public void attach(Observer observer) {
    observers.add(observer);
  }

  // 删除观察者
  @Override
  public void detach(Observer observer) {
    observers.remove(observer);
  }

  // 通知观察者
  @Override
  public void publish() {
    observers.forEach(observer -> observer.update(this));
  }
}
package co.yiiu;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by tomoya at 2019/4/8
 */
public class WeatherSubject implements Subject {

  private String content;
  private List<Observer> observers = new ArrayList<>();

  @Override
  public String getContent() {
    return content;
  }

  @Override
  public void setContent(String content) {
    this.content = co 大专栏  Java里观察者模式(订阅发布模式)ntent;
  }

  @Override
  public void attach(Observer observer) {
    observers.add(observer);
  }

  @Override
  public void detach(Observer observer) {
    observers.remove(observer);
  }

  @Override
  public void publish() {
    observers.forEach(observer -> observer.update(this));
  }
}

文原链接:https://tomoya92.github.io/2019/04/08/java-subscribe-publish/

实现观察者

我这写了一个通用的实现,创建观察者的时候,传递一个名字表示不同的观察者

package co.yiiu;

/**
 * Created by tomoya at 2019/4/8
 */
public class ConcreteObserver implements Observer {

  private String name;

  public ConcreteObserver(String name) {
    this.name = name;
  }

  @Override
  public void subscribe(Subject subject) {
    subject.attach(this);
  }

  @Override
  public void unsubscribe(Subject subject) {
    subject.detach(this);
  }

  @Override
  public void update(Subject subject) {
    System.out.println(this.name + " 订阅的内容: " + subject.getContent());
  }
}

测试

package co.yiiu;

import org.junit.Test;

/**
 * Created by tomoya at 2019/4/8
 */
public class TestObserver {

  @Test
  public void test() {
    // 创建主题对象
    Subject newsSubject = new NewsSubject();
    Subject weatherSubject = new WeatherSubject();

    // 给主题赋值
    newsSubject.setContent("我是一条新闻消息");
    weatherSubject.setContent("我是一条天气消息");

    // 创建订阅者
    Observer concreteObserver1 = new ConcreteObserver("用户1");
    // 订阅newsSubject
    concreteObserver1.subscribe(newsSubject);

    Observer concreteObserver2 = new ConcreteObserver("用户2");
    // 订阅newsSubject和weatherSubject
    concreteObserver2.subscribe(newsSubject);
    concreteObserver2.subscribe(weatherSubject);

    Observer concreteObserver3 = new ConcreteObserver("用户3");
    // 订阅weatherSubject
    concreteObserver3.subscribe(newsSubject);
    concreteObserver3.subscribe(weatherSubject);

    // user2 取消订阅newsSubject
    concreteObserver2.unsubscribe(newsSubject);

    // 发布消息
    newsSubject.publish();
    weatherSubject.publish();

  }
}

运行结果

用户1 订阅的内容: 我是一条新闻消息
用户3 订阅的内容: 我是一条新闻消息
用户2 订阅的内容: 我是一条天气消息
用户3 订阅的内容: 我是一条天气消息

总结

有了这个订阅发布模式了,就可以解决类似订单状态改变后的处理逻辑了

  1. 创建一个订单主题
  2. 创建一个观察者来订阅这个订单主题
  3. 当订单状态有变化时,通过订单主题发布这个订单
  4. 这时候只要订阅了这个订单主题的观察者就能收到消息,然后就可以处理这个状态有变化的订单了


java.util 包里也有 Observable Observer

不过它是通过被观察者主动添加观察者来实现的,当有消息了,调用 notifyObservers() 方法来通知观察者

这种做法还需要被观察者去维护观察者,不太好,还不如让观察者主动去订阅干脆

写博客不易,转载请保留原文链接,谢谢!

原文链接: https://tomoya92.github.io/2019/04/08/java-subscribe-publish/

原文地址:https://www.cnblogs.com/lijianming180/p/12275744.html

时间: 2024-10-06 21:25:21

Java里观察者模式(订阅发布模式)的相关文章

AngularJS的简单订阅发布模式例子

控制器之间的交互方式广播 broadcast, 发射 emit 事件 类似于 js中的事件 , 可以自己定义事件 向上传递直到 document 在AngularJs中 向上传递直到 rootScope 观察者模式, 订阅发布模式 类似于js中的事件机制 订阅者.on('xx发布博客', function([内容]){ 通知我, 接收到博客的[内容] }) 发布者.emit('xxx发布博客', {内容}) 优点: 业务和实际触发者分离, 代码维护性相对好 缺点: 代码复杂性更高 Angular

JS实现观察者模式(订阅/发布模式)

实现 /*  * js 观察者模式 又称 订阅/发布模式  * 通过创建"可观察"对象,当发生一个感兴趣的事件时可将该事件通告给  * 所有观察者,从而形成松耦合 */ // 通用的发布者 EventPublisher = Base.extend({ publish: function(data, type) { EventPublisher.publish(data, type); } }, { subscribers : {         any : []    // 事件类型:

Spring基于事件驱动模型的订阅发布模式代码实例详解

代码下载地址:http://www.zuidaima.com/share/1791499571923968.htm 原文:Spring基于事件驱动模型的订阅发布模式代码实例详解 事件驱动模型简介 事件驱动模型也就是我们常说的观察者,或者发布-订阅模型:理解它的几个关键点: 首先是一种对象间的一对多的关系:最简单的如交通信号灯,信号灯是目标(一方),行人注视着信号灯(多方): 当目标发送改变(发布),观察者(订阅者)就可以接收到改变: 观察者如何处理(如行人如何走,是快走/慢走/不走,目标不会管的

4 交换机-fanout(订阅发布模式)

目录 订阅发布模式 1.交换器(Exchange) 1.1.创建交换器 1.2 .推送消息到交换器 2.临时队列 3.绑定(bingdings) 5.代码例子 5.1.生产者代码示例 5.2.消费者代码示例 订阅发布模式 1.交换器(Exchange) 在Work Queue背后,其实是rabbitMQ把每条任务消息只发给一个消费者.本篇中我们将要研究如何把一条消息推送给多个消费者,这种模式被称为publish/subscribe(发布/订阅) RabbitMQ的消息发送模型核心思想是生产者不直

订阅发布模式

场景概述: 有时需要将多个应用程序集成到一个框架中,这些应用程序常见的基础通信方式包含总线模式.代理模式. 或者点对点模式.一些应用程序发送多种类型的消息,其他应用程序可能更关注这些消息类型的组合. 例如,在一个金融系统存在多个应用程序管理同一客户信息的情况,存在一个客户关系管理程序(CRM)掌握客户信息. 一种典型的情况:客户信息存在于其他系统中,且这些系统执行各自客户信息管理函数来处理客户信息. 当某个面向客户的应用程序生成更新客户信息的消息,例如客户地址的修改时,CRM和其他管理客户信息的

Publisher/Subscriber 订阅-发布模式

Publisher/Subscriber 订阅-发布模式 本博后续将陆续整理这些年做的一些预研demo,及一些前沿技术的研究,与大家共研技术,共同进步. 关于发布订阅有很多种实现方式,下面主要介绍WCF中的发布订阅,主要参考书籍<Programming WCF Services>,闲话不多说进入正题.使用传统的双工回调(例子 http://www.cnblogs.com/artech/archive/2007/03/02/661969.html)实现发布订阅模式存在许多缺陷,主要问题是,它会引

RabbitMQ下的生产消费者模式与订阅发布模式

??所谓模式,就是在某种场景下,一类问题及其解决方案的总结归纳.生产消费者模式与订阅发布模式是使用消息中间件时常用的两种模式,用于功能解耦和分布式系统间的消息通信,以下面两种场景为例: 数据接入 ??假设有一个用户行为采集系统,负责从App端采集用户点击行为数据.通常会将数据上报和数据处理分离开,即App端通过REST API上报数据,后端拿到数据后放入队列中就立刻返回,而数据处理则另外使用Worker从队列中取出数据来做,如下图所示. ??这样做的好处有:第一,功能分离,上报的API接口不关心

Node中EventEmitter以及如何实现JavaScript中的订阅/发布模式

1.EventEmitter Node中很多模块都能够使用EventEmitter,有了EventEmitter才能方便的进行事件的监听.下面看一下Node.js中的EventEmitter如何使用. (1)基本使用 EventEmitter是对事件触发和事件监听功能的封装,在node.js中的event模块中,event模块只有一个对象就是EventEmitter,下面是一个最基本的使用方法: var EventEmitter = require('events').EventEmitter;

【并发】9、借助redis 实现生产消费,消息订阅发布模式队列

这个就是一个消息可以被多次消费的范例了 其实这个实现的方式可以参考我之前的设计模式,观察者模式 https://www.cnblogs.com/cutter-point/p/5249780.html 不过有一点需要注意一下啊,这个消息发布的时候,好像是不支持字节数据的,里面好像会对字节进行转换,这样的结果就是导致我最后无法吧相应的字节转换成我之前序列化的对象 不知道是不是ObjectInputStream和ObjectOutputStream实现不是很好的原因,还是什么,反正反序列化的时候,有些