Java里观察者模式(订阅发布模式)
在公司开发项目,如果碰到一些在特定条件下触发某些逻辑操作的功能的实现基本上都是用的定时器
比如用户注册完后,发送邮件,为了防止邮件发送失败或者发送邮件比较耗时,一般也都是通过定时器去扫库里注册没有发邮件的用户数据
再比如一个订单,在改变状态后,要归档,这也是通过定时器来实现的,扫描订单的数据,通过判断状态来做相对应的处理
但这样处理的话,定时器就会越来越多,总觉得不太好
然后,从一些资讯网站上的订阅功能想到了是否可以使用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 订阅的内容: 我是一条天气消息
总结
有了这个订阅发布模式了,就可以解决类似订单状态改变后的处理逻辑了
- 创建一个订单主题
- 创建一个观察者来订阅这个订单主题
- 当订单状态有变化时,通过订单主题发布这个订单
- 这时候只要订阅了这个订单主题的观察者就能收到消息,然后就可以处理这个状态有变化的订单了
java.util 包里也有 Observable Observer
不过它是通过被观察者主动添加观察者来实现的,当有消息了,调用 notifyObservers() 方法来通知观察者
这种做法还需要被观察者去维护观察者,不太好,还不如让观察者主动去订阅干脆
写博客不易,转载请保留原文链接,谢谢!
原文链接: https://tomoya92.github.io/2019/04/08/java-subscribe-publish/
Java里观察者模式(订阅发布模式)的更多相关文章
- AngularJS的简单订阅发布模式例子
控制器之间的交互方式广播 broadcast, 发射 emit 事件 类似于 js中的事件 , 可以自己定义事件 向上传递直到 document 在AngularJs中 向上传递直到 rootScop ...
- saltstack系列(三)——zmq订阅/发布模式
zmq订阅发布模式 server端代码: #coding=utf-8 ''''' 服务端,发布模式 ''' import zmq from random import randrange contex ...
- Publisher/Subscriber 订阅-发布模式
Publisher/Subscriber 订阅-发布模式 本博后续将陆续整理这些年做的一些预研demo,及一些前沿技术的研究,与大家共研技术,共同进步. 关于发布订阅有很多种实现方式,下面主要介绍WC ...
- 设计模式---订阅发布模式(Subscribe/Publish)
设计模式---订阅发布模式(Subscribe/Publish) 订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象.这个主题对象在自身状态变化时,会通知所有订阅者对象,使 ...
- RabbitMQ下的生产消费者模式与订阅发布模式
所谓模式,就是在某种场景下,一类问题及其解决方案的总结归纳.生产消费者模式与订阅发布模式是使用消息中间件时常用的两种模式,用于功能解耦和分布式系统间的消息通信,以下面两种场景为例: 数据接入 假设 ...
- Kafka下的生产消费者模式与订阅发布模式
原文:https://blog.csdn.net/zwgdft/article/details/54633105 在RabbitMQ下的生产消费者模式与订阅发布模式一文中,笔者以“数据接入”和“事 ...
- js设计模式之代理模式以及订阅发布模式
为啥将两种模式放在一起呢?因为这样文章比较长啊. 写博客的目的我觉得首要目的是整理自己的知识点,进而优化个人所得知识体系.知识成为个人的知识,就在于能够用自己的话表达同一种意义. 本文是设计模式系列文 ...
- 订阅发布模式eventEmiter
// 订阅发布模式 class EventEmitter { constructor() { this._events = {}; } on(name, callback) { if (this._e ...
- ionic2踩坑之订阅发布模式的实现
原文地址:http://www.cnblogs.com/eccainiao/p/6429536.html 转载请说明. 在ionic2中实现订阅发布模式,需要用到Events. Events下面有三个 ...
随机推荐
- Linux中PATH、 LIBRARY_PATH、 LD_LIBRARY_PATH和ROS_PACKAGE_PATH
PATH 保存可执行文件程序路径,我们命令行中每一句能运行的命令都是系统先通过PATH来找到命令执行文件所在的位置,再运行这个命令. 实验:执行echo $PATH 能看到当前环境PATH都是配置了哪 ...
- jenkins推送docker镜像到远程仓库
参考链接:https://blog.csdn.net/qq_34252622/article/details/92791262
- tesseract系列(2) -- tesseract的使用
上文说了怎么编译成库,这次说说怎么使用,先验证下编译出来的结果. 下图是debug生成的文件,里面有个tesseract的应用程序. cmd进入目录下,执行命令:tesseract eurotext. ...
- Matlab高级教程_第三篇:Matlab转码C/C++方式(混编)_第二部分
这一部分通过一些实例来进行转码和调试的讲解: 1. 输入变量.输出变量和过程内变量的内存预分配 函数代码:函数名test function [A,B] = test( mark,num,array ) ...
- linux的进程和管道符(二)
回顾:进程管理:kill killall pkill问题:1.pkill -u root 禁止2.用户名不要用数字开头或者纯数字windows的用户名不要用中文3.pokit/etc/passwd 6 ...
- vue2.0学习之基础内容
import BScroll from 'better-scroll'; import star from '../star/star.vue'; import split from '../spli ...
- signal之——异步回收机制
前言:回收子进程之前用了wait()和非阻塞模型,今天学了信号以后可以使回收机制更上一层楼,通过信号函数,父进程只需要做自己的事情,接收到信号后就触发信号函数. 信号处理函数可能会出现的bug: 1. ...
- 【UML】
静态:类图,包图,部署图,构件图,对象图 行为:用例图,活动图,顺序图,状态图,交互图 [类图] http://www.uml.org.cn/oobject/201104212.asp [对象图] h ...
- mysql 实现类似开窗函数的功能
mysql8 已经支持开窗函数 https://dev.mysql.com/doc/refman/8.0/en/window-functions.html ———————————————— sql s ...
- JDBC介绍和Mybatis运行原理及事务处理
本博客内容非自创,转载自以下三位,侵删: https://juejin.im/post/5ab7bd11f265da23906bfbc5 https://my.oschina.net/fifadxj/ ...