定义
定义对象间一种一对多的关系,使得每当一个对象改变状态,则所有依赖他的对象都会得到通知并被自动更新。
使用场景
1、某些时候需要一些对象有所关联,而且这种关联是可以拆分而不是组合在一起的。
2、某一事件发生,需要向多方触发。
3、消息交换,如消息队列、事件总线的处理机制。
角色
1、Subject:抽象主题,被观察者(Observable)的抽象,管理着众多观察者的实现,可以实现添加或删除观察者的功能。
2、ConcreteSubject:具体主题,被观察者(Observable)的实现,通过该实现来向观察者发送通知。
3、Observer:抽象观察者(Observer),观察者的抽象。一般是接口,实现该接口生成各种各样的观察者。
4、ConcreteObserver:具体观察者,抽象观察者的具体实现,当被观察者发生变化时执行具体逻辑。
简单实现
要实现的功能:定义一个数据订阅源,当数据源发生变化时,订阅者收到消息。
/**
* 观察者模式(订阅模式)
*/
public class ObservableDesignDemo {
public static void main(String []args){
ObserverImp observable1=new ObserverImp("张三");
ObserverImp observable2=new ObserverImp("李四");
ObservableImp observableImp=new ObservableImp();
//将观察者注册到被观察者的观察列表中
observableImp.addObserver(observable1);
observableImp.addObserver(observable2);
//发布消息,notifyObservers()遍历所有的观察者然后调用其update()
observableImp.observableDoSth("你好,我是被你观察的,我生了变化");
}
}
/**
* 被观察者具体实现
*/
class ObservableImp extends Observable{
void observableDoSth(String sth){
//表明数据发生了变化且已经通知过
setChanged();
notifyObservers(sth);
}
}
/**
* 观察者具体实现
*/
class ObserverImp implements Observer {
String observerName;
public ObserverImp(String observerName) {
this.observerName = observerName;
}
@Override
public void update(Observable observable, Object o) {
System.out.println(observerName+",你订阅的有更新,内容是:"+o);
}
@Override
public String toString() {
return "观察者的名字是:"+observerName;
}
}
JDK自带类Observable
public class Observable {
// 1.1 数据是否变化标记
private boolean changed = false;
// 1.2 长度自增长数组
private Vector<Observer> obs;
/** Construct an Observable with zero Observers. */
public Observable() {
obs = new Vector<>();
}
// 2.1 添加观察者对象
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
// 2.2 删除观察者对象
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
// 3.1 通知所有观察者
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
// 线程同步
synchronized (this) {
// 3.2 获取是否发生变化的标记
if (!hasChanged())
return;
// 3.3 转化为 Object 数组
arrLocal = obs.toArray();
// 重置标记
clearChanged();
}
// 遍历所有观察者并调用其 update 方法
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
// 删除所有观察者对象
public synchronized void deleteObservers() {
obs.removeAllElements();
}
// 设置标记为 true,表明数据发生了变化且已经通知过
protected synchronized void setChanged() {
changed = true;
}
// 清除标记,恢复默认状态
protected synchronized void clearChanged() {
changed = false;
}
// 获取标记
public synchronized boolean hasChanged() {
return changed;
}
// 获取观察者的数量
public synchronized int countObservers() {
return obs.size();
}
}
可以看到所有订阅了数据订阅源的人都收到了消息,Observable和Observer是JDK中内置的类,可见观察者模式是非常重要的,这里Observer是抽象的观察者角色,ObserverImp扮演的是具体的观察者角色;Observable扮演的是抽象的主题(被观察者)角色,ObservableImp代表的是具体的主题角色,当ObservableImp有更新时会遍历通知所有的观察者,然后给这些观察者发送一个消息,即ObserverImp的update()方法,这样达到了一对多的通知功能,在这个过程中,通知系统都是依赖Observer和Observable,因此对于ObserverImp和ObservableImp完全没有耦合,保证了订阅系统的灵活性、可扩展性。