观察者模式是一种对象行为型模式,其意图是定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变的时候,所有依赖于它的对象都得到通知并被自动更新。观察者模式也叫发布-订阅模式(Publish-Subscribe)
一、观察者模式的基本介绍
1.1 意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变的时候,所有依赖于它的对象都得到通知并被自动更新。
1.2 结构
观察者模式基本的结构如下图所示:
主要包括如下几个部分:
JDK提供了java.util.Observer和java.util.Observable可以实现观察者模式。
从上述Observable的截图可以看出,Observerable维护一个changed状态和需要通知的订阅者列表。
private boolean changed = false;
private Vector<Observer> obs;
当状态改变的时候,会依次通知各个订阅者。
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;
synchronized (this) {
/* We don't want the Observer doing callbacks into
* arbitrary code while holding its own Monitor.
* The code where we extract each Observable from
* the Vector and store the state of the Observer
* needs synchronization, but notifying observers
* does not (should not). The worst result of any
* potential race-condition here is that:
* 1) a newly-added Observer will miss a
* notification in progress
* 2) a recently unregistered Observer will be
* wrongly notified when it doesn't care
*/
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
另外,还有添加订阅者、删除订阅者等方法。
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an {@code Observable} object's
* {@code notifyObservers} method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the {@code notifyObservers}
* method.
*/
void update(Observable o, Object arg);
}
Observer接口就一个update方法,用于获取来自主题的消息更新。
二、使用JDK内置的Observer完成一个观察者模式示例
一个项目完成了,大家一起去聚餐嗨皮。看着时间还早,Eric提议说要不我们再去唱会歌吧。大家都可以开心说“好啊”。Eric说我先去KTV看下,具体房间号定好,我再通知大家。
就这样一个场景,很适合观察者模式,借助JDK内置的Observer和Observable,我们来看下如何完成。
package com.wangmengjun.tutorial.designpattern.observer;
import java.util.Observable;
public class KtvOrder extends Observable {
private String name;
public KtvOrder(String name) {
this.name = name;
}
public void sendMessage(String message) {
System.out.println(String.format("[%s]发送通知: %s", name,message));
this.setChanged();
this.notifyObservers(message);
}
/**
* @return the name
*/
public String getName() {
return name;
}
@Override
public String toString() {
return "KtvOrder [name=" + name + "]";
}
}
package com.wangmengjun.tutorial.designpattern.observer;
import java.util.Observable;
import java.util.Observer;
public class KtvParticipant implements Observer {
private String name;
public KtvParticipant(String name) {
this.name = name;
}
public void update(Observable o, Object arg) {
KtvOrder order = null;
if(o instanceof KtvOrder) {
order = (KtvOrder)o;
System.out.println(String.format("[%s]收到来自[%s]的通知信息==> %s", name,order.getName(),arg.toString()));
}
}
}
package com.wangmengjun.tutorial.designpattern.observer;
public class ObserverMain {
public static void main(String[] args) {
KtvOrder order = new KtvOrder("Eric");
KtvParticipant john = new KtvParticipant("John");
KtvParticipant lucy = new KtvParticipant("Lucy");
KtvParticipant lily = new KtvParticipant("Lily");
order.addObserver(john);
order.addObserver(lucy);
order.addObserver(lily);
order.sendMessage("西城广场银乐迪506");
}
}
输出结果:
[Eric]发送通知: 西城广场银乐迪506
[Lily]收到来自[Eric]的通知信息==> 西城广场银乐迪506
[Lucy]收到来自[Eric]的通知信息==> 西城广场银乐迪506
[John]收到来自[Eric]的通知信息==> 西城广场银乐迪506
小结
本文对观察者模式进行了简单介绍,并使用JDK提供的java.util.Observer和java.util.Observable完成一个示例。
ps: java.util.Observer和java.util.Observable从JDK9开始,已经标注为过时。