多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。
提到观察者,就一定有“被观察者”。
被观察者发生改变时,通知给每个观察者,这就是观察者模式。放到生活中的例子就是
对于上面的例子,天气预报需要用户自己付费订阅、群聊需要先进群、在家看报需要联系报社订阅报纸。这里就能看出来。这种关系是一个一对多的关系。被观察者是同一个,而观察者却可以是很多个不同的对象。还有就是观察者需要自己主动的去找被观察者“提前”说明好,“一旦有消息,请通知我一声”。所有这里可以抽象出来几个角色和动作。
如果对 JDK 熟悉的同学可能早已看穿,这个类图画的其实就是 JDK 提供的观察者框架,我们可以用它轻松的实现一个订阅通知功能。而这一功能在 JDK 1.0 的版本就已经存在了。
JDK 源码,篇幅原因只保留了核心代码
package java.util;
// 观察者
public interface Observer {
void update(Observable var1, Object var2);
}
JDK 源码,篇幅原因只保留了核心代码
package java.util;
// 被观察者
public class Observable {
// 管理观察者对象
private final Vector<Observer> obs = new Vector();
public synchronized void addObserver(Observer var1) {
if (!this.obs.contains(var1)) {
this.obs.addElement(var1);
}
}
// 通知给订阅的观察者
public void notifyObservers(Object var1) {
Object[] var2 = this.obs.toArray();
for(int var3 = var2.length - 1; var3 >= 0; --var3) {
((Observer)var2[var3]).update(this, var1);
}
}
}
自己实现部分
public class Producer extends Observable {
@Override
public synchronized void setChanged() {
super.setChanged();
}
}
public class Consumer1 implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("我是 consumer1 我收到了" + o + "的通知,通知内容:" + arg);
}
}
public class Consumer2 implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("我是 consumer2 我收到了" + o + "的通知,通知内容:" + arg);
}
}
public class Consumer3 implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("我是 consumer3 我收到了" + o + "的通知,通知内容:" + arg);
}
}
测试,定义了 2 个被观察者(生产者),3 个观察者(消费者)来分别使用12生产者来发布消息。
@Test
void jdkOb() {
Producer producer1 = new Producer();
producer1.setChanged();
Producer producer2 = new Producer();
producer2.setChanged();
Consumer1 consumer1 = new Consumer1();
Consumer2 consumer2 = new Consumer2();
Consumer3 consumer3 = new Consumer3();
producer1.addObserver(consumer1);
producer1.addObserver(consumer2);
producer1.addObserver(consumer3);
producer2.addObserver(consumer1);
producer2.addObserver(consumer2);
producer2.addObserver(consumer3);
producer1.notifyObservers("我是生产者1,我现在给你们通知一条消息,收到赶紧去消费掉");
producer2.notifyObservers("我是生产者2,我现在给你们通知一条消息,收到赶紧去消费掉");
}
测试结果
我是 consumer3 我收到了Producer@57cd70的通知,通知内容:我是生产者1,我现在给你们通知一条消息,收到赶紧去消费掉
我是 consumer2 我收到了Producer@57cd70的通知,通知内容:我是生产者1,我现在给你们通知一条消息,收到赶紧去消费掉
我是 consumer1 我收到了Producer@57cd70的通知,通知内容:我是生产者1,我现在给你们通知一条消息,收到赶紧去消费掉
我是 consumer3 我收到了Producer@1a7504c的通知,通知内容:我是生产者2,我现在给你们通知一条消息,收到赶紧去消费掉
我是 consumer2 我收到了Producer@1a7504c的通知,通知内容:我是生产者2,我现在给你们通知一条消息,收到赶紧去消费掉
我是 consumer1 我收到了Producer@1a7504c的通知,通知内容:我是生产者2,我现在给你们通知一条消息,收到赶紧去消费掉
使用观察者模式需要注意的几个点
观察者模式的代码虽然很简单,但是它所创造的价值却远不止这些。相信你同我一样,通过观察者模式联想到了消息通知、binlog订阅、注册中心等技术组件。其核心内容也只是在此简单的不能再简单的思想上去做更多更复杂的功能迭代。
万变不离其宗。在复杂的系统,在复杂的功能,都能找到其根本所在。知识,亦是如此。
当然,你也可以尝试在现有的代码中进行一些修改,比如通知的情况改为有新的观察者加入时?通知的数据变得更丰富一些?异步通知?等等等等。