今天看了一下观察者模式,总体来说不难,关键是要知道原理和这个模式的用法下面是我自己个人一些理解。
1、定义
观察者模式,首先得有观察者,一个或者多个观察者,它们都依赖于另一个对象,也就是说,这些观察者都观察着一个被观察者。那么,当被观察者状态发生改变时,被观察者需要通知所有它的观察者这个状态的变化,这就是观察者模式。
这样理解不好理解,举个简单的例子,很火的直播行业,一个主播,有非常多的粉丝,都关注了这个主播,主播直播开播了,ta所有粉丝都能收到通知:您关注的主播已经开播了。这就是观察者模式最好的例子,其中,主播就是被观察者,粉丝就是观察者。
2、代码演示
观察者:
public class Observer {
public void update(Observable o){
//被观察者状态改变通知观察者时调用的方法
}
}
被观察者
public class Observable{
List<Observer> observers;//所有的观察者
//添加观察者
public void addObserver(Observer o){
observers.add(o)
}
public void changed(){
//被观察者状态改变
//调用通知
notifyObserver();
}
//通知所有观察者状态已经改变
public void notifyObserver(){
for(int i=0 ; i < observers.size();i++){
observers.get(i).update(this)
}
}
}
可以看出,观察者模式最核心的地方就是,被观察者在状态改变时(changed()),立即调用通知方法(notifyObserver()),已达到状态改编,观察者立即能够接收到这个信息。
3、jdk
jdk已经定义好了观察者模式,来看看源码
//观察者接口,每一个观察者都必须实现这个接口
public interface Observer {
//这个方法是观察者在观察对象产生变化时所做的响应动作,从中传入了观察的对象和一个预留参数
void update(Observable o, Object arg);
}
import java.util.Vector;
//被观察者类
public class Observable {
//这是一个改变标识,来标记该被观察者有没有改变
private boolean changed = false;
//持有一个观察者列表
private Vector 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);
}
//notifyObservers(Object arg)的重载方法
public void notifyObservers() {
notifyObservers(null);
}
//通知所有观察者,被观察者改变了,你可以执行你的update方法了。
public void notifyObservers(Object arg) {
//一个临时的数组,用于并发访问被观察者时,留住观察者列表的当前状态,这种处理方式其实也算是一种设计模式,即备忘录模式。
Object[] arrLocal;
//注意这个同步块,它表示在获取观察者列表时,该对象是被锁定的
//也就是说,在我获取到观察者列表之前,不允许其他线程改变观察者列表
synchronized (this) {
//如果没变化直接返回
if (!changed)
return;
//这里将当前的观察者列表放入临时数组
arrLocal = obs.toArray();
//将改变标识重新置回未改变
clearChanged();
}
//注意这个for循环没有在同步块,此时已经释放了被观察者的锁,其他线程可以改变观察者列表
//但是这并不影响我们当前进行的操作,因为我们已经将观察者列表复制到临时数组
//在通知时我们只通知数组中的观察者,当前删除和添加观察者,都不会影响我们通知的对象
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
//删除所有观察者
public synchronized void deleteObservers() {
obs.removeAllElements();
}
//标识被观察者被改变过了
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();
}
}
JDK的源码中,需要注意的地方是,在观察者的update方法里面需要处理好异常,否则,在被观察者通知方法中,会导致,其他观察者无法被通知。