观察者模式
- 观察者模式,多用于单个应用内部
- 发布订阅模式,则更多的是一种跨应用的模式(cross-application pattern),比如我们常用的消息中间件
- 也叫发布订阅模式,监听事件就是这种原理
- 一个对象被监听着,当监听对象状态改变的时候,监听的事件就会被触发
- 消息中间件也是这种模式,本质上也类似于监听
- 只不过把这种监听的模式从系统里抽出来,做了个第三方工具
- 各种优化丶调整丶增强,本质上要完成的逻辑也就是一种监听
Subject类是主题(控制调节发布丶订阅两者)
- 类似于中间人,用来
监测发布者的状态
和通知所有订阅者执行
- 发布着和订阅者之间解耦合,只与这个主题有关联
- 类似于中间人,用来
Observer类是抽象订阅者
- 订阅者有多个,有一个接口做规范
ConcreteSubject类是发布者
- 发布者执行业务逻辑的某处,调用主题中的通知方法,通知所有订阅者执行
ConcreteObserver是订阅者
- 一个个订阅者,等待发布者发布消息
主题Subject
-
首先定义一个订阅者数组,并实现增、删及通知操作。
- 订阅者有多个,所以通知所有订阅者的前提是要保存好所有订阅者的信息
public class Subject { //订阅者数组 private Vector<Observer> oVector = new Vector<>(); //增加一个订阅者 public void addObserver(Observer observer) { this.oVector.add(observer); } //删除一个订阅者 public void deleteObserver(Observer observer) { this.oVector.remove(observer); } //通知所有订阅者 public void notifyObserver() { for(Observer observer : this.oVector) { observer.update(); } } }
订阅者接口 -> Observer
-
订阅者有多个,有一个接口做规范
interface Observer { //更新 -> 接到通知,所有订阅者都执行这个方法 public void update(); }
发布者
-
继承主题Subject类,为了复用主题中的通知方法
- 如果不继承,就要手动new一个主题对象注入到发布者对象中,最后都要有所关系才行
class ConcreteSubject extends Subject { //具体业务 public void doSomething() { //... super.notifyObserver();//在某处执行通知 } }
订阅者
-
具体每个订阅者,在方法中执行逻辑即可
class ConcreteObserver implements Observer { @Override public void update() { System.out.println("收到消息,进行处理"); } }
main方法
-
首先创建一个主题者
-
然后定义一个订阅者
-
将该订阅者添加到主题的订阅者数组中
-
最后发布者执行逻辑,在某个时间段发布通知
public static void main(String[] args) { //创建一个发布者 ConcreteSubject subject = new ConcreteSubject(); //定义一个订阅者 Observer observer = new ConcreteObserver(); //订阅者添加到主题中 -> 发布者继承了主题,所以用发布者对象就可以将订阅者添加到主题 subject.addObserver(observer); //开始活动 subject.doSomething(); }
-
其实可以看出,我们可以把主题给去掉,把
所有方法都写在发布者里面
- 这样就只剩下发布者和订阅者了,发布者对象中保存所有订阅者对象
- 发布通知的时候,遍历所有订阅者调用方法即可
-
这种没有主题的说法才是观察者模式
- 观察者模式只需要一个观察者和被观察者就可以了
- 观察者模式还是有一定的耦合性的
-
而发布订阅模式是需要抽出一个主题的,这样耦合程度就降低了
- 而且不一定要发布者去继承主题
- 还可以用传参的方式,将发布者和订阅者都加入到主题对象中
- 主题只单纯的用来做通知,
每进来一个发布者或者一段消息,主题就判断一下该通知哪些订阅者接受
- 这就是消息队列了
-
设计模式要灵活运用
Observable
-> 主题
public class java.util.Observable {
private Vector<Observer> obs;
/** 构造一个观察者为零的可观测系统. */
public Observable() {
obs = new Vector<>();
}
//添加观察者
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
//删除观察者
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
//通知所有观察者
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
}
Observer
-> 观察者接口
public interface java.util.Observer {
void update(Observable o, Object arg);
}
- 我们只要继承主题,实现我们自己的逻辑,在合适的地方调用通知
- 将实现观察者接口,加入主题中等待发布通知即可
改写我们的例子就变成
import java.util.Observable;
import java.util.Observer;
public class 观察者模式 {
public static void main(String[] args) {
//创建一个主题
ConcreteSubject subject = new ConcreteSubject();
//定义添加观察者
subject.addObserver(new ConcreteObserver1());
subject.addObserver(new ConcreteObserver2());
//开始活动
subject.doSomething();
}
}
class ConcreteSubject extends Observable {
//具体业务
public void doSomething() {
System.out.println("具体业务");
//设置被观察者发生变化 -> 可以执行通知
setChanged();
//发布通知
notifyObservers();
}
}
class ConcreteObserver1 implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("收到消息,进行处理1");
}
}
class ConcreteObserver2 implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("收到消息,进行处理2");
}
}
具体业务
收到消息,进行处理2
收到消息,进行处理1