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

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

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

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

然后,从一些资讯网站上的订阅功能想到了是否可以使用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/

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

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

    控制器之间的交互方式广播 broadcast, 发射 emit 事件 类似于 js中的事件 , 可以自己定义事件 向上传递直到 document 在AngularJs中 向上传递直到 rootScop ...

  2. saltstack系列(三)——zmq订阅/发布模式

    zmq订阅发布模式 server端代码: #coding=utf-8 ''''' 服务端,发布模式 ''' import zmq from random import randrange contex ...

  3. Publisher/Subscriber 订阅-发布模式

    Publisher/Subscriber 订阅-发布模式 本博后续将陆续整理这些年做的一些预研demo,及一些前沿技术的研究,与大家共研技术,共同进步. 关于发布订阅有很多种实现方式,下面主要介绍WC ...

  4. 设计模式---订阅发布模式(Subscribe/Publish)

    设计模式---订阅发布模式(Subscribe/Publish) 订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象.这个主题对象在自身状态变化时,会通知所有订阅者对象,使 ...

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

    所谓模式,就是在某种场景下,一类问题及其解决方案的总结归纳.生产消费者模式与订阅发布模式是使用消息中间件时常用的两种模式,用于功能解耦和分布式系统间的消息通信,以下面两种场景为例: 数据接入   假设 ...

  6. Kafka下的生产消费者模式与订阅发布模式

    原文:https://blog.csdn.net/zwgdft/article/details/54633105   在RabbitMQ下的生产消费者模式与订阅发布模式一文中,笔者以“数据接入”和“事 ...

  7. js设计模式之代理模式以及订阅发布模式

    为啥将两种模式放在一起呢?因为这样文章比较长啊. 写博客的目的我觉得首要目的是整理自己的知识点,进而优化个人所得知识体系.知识成为个人的知识,就在于能够用自己的话表达同一种意义. 本文是设计模式系列文 ...

  8. 订阅发布模式eventEmiter

    // 订阅发布模式 class EventEmitter { constructor() { this._events = {}; } on(name, callback) { if (this._e ...

  9. ionic2踩坑之订阅发布模式的实现

    原文地址:http://www.cnblogs.com/eccainiao/p/6429536.html 转载请说明. 在ionic2中实现订阅发布模式,需要用到Events. Events下面有三个 ...

随机推荐

  1. goweb-goweb基础

    goweb DNS工作原理 在浏览器中输入www.qq.com域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析. 如果hosts里没 ...

  2. 查看opencv-python编译信息

    python -c "import cv2; print(cv2.getBuildInformation())" General configuration for OpenCV ...

  3. 吴裕雄--天生自然 pythonTensorFlow图形数据处理:读取MNIST手写图片数据写入的TFRecord文件

    import numpy as np import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_dat ...

  4. ZOJ-1610 Count the Colors(线段树染色,求染色段)

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1610 https://vjudge.net/contest/318019# ...

  5. C - The Battle of Chibi HDU - 5542 (树状数组+离散化)

    Cao Cao made up a big army and was going to invade the whole South China. Yu Zhou was worried about ...

  6. yum安装与卸载软件常见命令

    1.使用yum安装和卸载软件,有个前提是yum安装的软件包都是rpm格式的. 安装的命令是,yuminstall ~,yum会查询数据库,有无这一软件包,如果有,则检查其依赖冲突关系,如果没有依赖冲突 ...

  7. CentOS6与CentOS7的网络区别

    回顾:物理层 关注的是接口物理特性,传输介质数据链路层 MAC地址,数据帧,以太网,交换机网络层 IP地址,数据包,IP\ICMP\ARP协议,路由器传输层 TCP.UDP,端口号,数据段应用层 HT ...

  8. 向通用自动驾驶部门Cruise投资22.5亿美元,软银打得什么主意?

    5月29日,加利福尼亚州的一辆特斯拉Model S撞上停在路边的警车.据透露,当时这辆特斯拉正处于自动辅助驾驶即Autopilot模式.而在今年,这已经不是第一次特斯拉自动驾驶模式出问题了.此外,Ub ...

  9. Yii框架的学习指南(策码秀才篇)1-3 我是这么学习的yii framework (不间断更新中)

    Ⅰ.基本概念一.入口文件入口文件内容:一般格式如下:<?php $yii=dirname(__FILE__).'/../../framework/yii.php';//Yii框架位置$confi ...

  10. Ribosome profiling|N-terminomics|蛋白质基因组学

    生物医学大数据-蛋白质基因组学:质谱注释 蛋白质组与其他组学的关系便是互为印证:蛋白质基因组学原本用于基因组注释,后面扩展到蛋白质与转录组或可变剪接之间关系,同时,蛋白质组依赖于基因组注释作为验证.许 ...