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

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

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

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

然后,从一些资讯网站上的订阅功能想到了是否可以使用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. Linux笔记(三)——Shell编程

    预备知识 1.Shell是解释执行的脚本语言,可以直接调用Linux系统命令 2.文件以.sh结尾, #!bin/bash 标识, 说明这是一个shell脚本, 不能省略 3.执行 赋予权限,直接运行 ...

  2. Properties类(一)

    Java中读写资源文件最重要的类是Properties,功能大致如下: 1. 读写Properties文件 2. 读写XML文件 3. 不仅可以读写上述两类文件,还可以读写其它格式文件如txt等,只要 ...

  3. 使用python列出目录下的所有文件

    https://stackoverflow.com/questions/3964681/find-all-files-in-a-directory-with-extension-txt-in-pyth ...

  4. 2019深圳Android千人开发者大会【NEW·无界】

    报名地址:https://www.hdb.com/dis/mjcsegnslu 安卓巴士技术社区是中国领先的安卓开发者社区,现已聚集超过85万开发者,数年来一直致力于IT从业者的知识分享服务. 安卓巴 ...

  5. 五、Shell脚本高级编程实战第五部

    一.条件表达式 在bash的各种流程控制结构中通常要进行各种测试,然后根据测试结果执行不同的操作.有时也和if结合,让我们方便判断. test: 1)判断文件是否存在:test -f  file 2) ...

  6. ID3/C4.5/Gini Index

    ID3/C4.5/Gini Index */--> ID3/C4.5/Gini Index 1 ID3 Select the attribute with the highest informa ...

  7. crontab不执行service命令

    我这里的需求是每30分钟重启一次 写成下面的格式就可以正确执行了,后面执行的命令写绝对路径 */30 * * * * /usr/bin/supervisorctl restart all

  8. winform 界面加载慢原因分析

    公司新来的开发人员,对winform开发还不是特别精通,在做个性化界面体验的时候容易出现闪烁和加载慢 闪烁的话,通过winform窗体的双缓存来解决在form 窗体中增加如下代码 protected ...

  9. vue实现动态绑定class--多个按钮点击一个有一个

    <template> //v-for循环出来多个按钮,便于获取index         <span v-for="(item,index) in list" : ...

  10. EXAM-2018-7-27

    EXAM-2018-7-27 未完成 [ ] F A 要用ll,然后注意正方形的情况,细心一点 E 有点动态规划的感觉,状态的转移,不难,要注意不要漏掉状态 K 正解是DFS 然后用贪心数据弱的话能过 ...