定义?
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。
观察者模式的作用是什么?
观察者模式的主要作用就是对象解耦,将观察者和被观察者完全隔离,只依赖于Observer和Observable抽象。
观察者模式的简单实现
很多技术网站支持用户邮箱订阅,每周发布周报后会将优质的内容推送给订阅用户。
/**
* 程序员是观察者
*/
public class Coder implements Observer {
public String name;
public Coder(String name) {
this.name = name;
}
@Override
public void update(Observable observable, Object data) {
System.out.print(name + data);
}
@Override
public String toString() {
return name;
}
}
/**
* 技术网站是被观察者,当它有更新时所有的观察者(程序员)都会接收到相应的通知
*/
public class DevTechFrontier extends Observable {
public void postNewPublication(String content) {
//标示状态,内容发生改变
setChanged();
//通知所有的观察者
notifyObservers();
}
}
/**
* 测试代码
*/
public class Test {
public void main(String[] args) {
//被观察者
DevTechFrontier devTechFrontier=new DevTechFrontier();
//观察者
Coder coder1=new Coder("coder-1");
Coder coder2=new Coder("coder-2");
Coder coder3=new Coder("coder-3");
//将观察者注册到列表中
devTechFrontier.addObserver(coder1);
devTechFrontier.addObserver(coder2);
devTechFrontier.addObserver(coder3);
//发布消息
devTechFrontier.postNewPublication("新的一期技术周报发布了!");
}
}
输出结果:
coder-1,新的一期技术周报发布了!
coder-2,新的一期技术周报发布了!
coder-3,新的一期技术周报发布了!
可以看到,所有订阅的用户都收到了更新消息,一对多的订阅。
这里Observer是抽象的观察者,Coder是具体的观察者;Observable是抽象被观察者,DevTechFrontier 是具体的可观察对象。Coder是观察者,它们订阅了DevTechFrontier 这个具体的可观察对象,当DevTechFrontier 有更新时,会遍历所有的观察者Coder,然后给这些观察者发布一个更新消息,即调用Coder的update方法,这样就达到了一对多的通知功能。在这个通知过程中,通知系统都是依赖Observer和Observable这两个抽象类,因此,对于Coder和DevTechFrontier 完全没有耦合。
JDK中的Observer接口和Observable类实现
1.在Observer接口源代码中只声明一个update()方法
public interface Observer {
void update(Observable var1, Object var2);
}
被观察者的对象当改变时调用这个方法。实现这个接口的类,可以作为观察者。
2.Observable类,被观察者,消息的发出者,继承此类可以扩展。
public class Observable {
//观察者的集合
List<Observer> observers = new ArrayList<Observer>();
boolean changed = false;
public Observable() {
}
public void addObserver(Observer observer) {
if (observer == null) {
throw new NullPointerException("observer == null");
}
synchronized (this) {
if (!observers.contains(observer))
observers.add(observer);
}
}
protected void clearChanged() {
changed = false;
}
public int countObservers() {
return observers.size();
}
public synchronized void deleteObserver(Observer observer) {
observers.remove(observer);
}
public synchronized void deleteObservers() {
observers.clear();
}
public boolean hasChanged() {
return changed;
}
public void notifyObservers() {
notifyObservers(null);
}
//通知所有订阅此主题的观察者对象
@SuppressWarnings("unchecked")
public void notifyObservers(Object data) {
int size = 0;
Observer[] arrays = null;
//这里为啥要同步?
//保证observers集合的数据唯一
synchronized (this) {
if (hasChanged()) {
clearChanged();
size = observers.size();
arrays = new Observer[size];
observers.toArray(arrays);
}
}
//这里为什么没有同步?
//观察者的updata操作可能是耗时操作
if (arrays != null) {
for (Observer observer : arrays) {
observer.update(this, data);
}
}
}
protected void setChanged() {
changed = true;
}
}
Android源码分析
ListView是Android中最重要的控件之一,而ListView最重要的一个功能是Adapter。通常,我们往ListView添加数据后,都会调用Adapter的notifyDataSetChange。下面对这个方法的源码进行分析。
notifyDataSetChange这个方法定义在BaseAdapter中,具体代码如下:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
//数据集观察者
private final DataSetObservable mDataSetObservable = new DataSetObservable();
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
/**
*当数据集发现变化时,通知所有观察者
*/
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
}
接下来看mDataSetObservable.notifyChanged()的源码:
/**
*数据集观察者
*/
public class DataSetObservable extends Observable<DataSetObserver> {
//调用每个观察者的onChanged方法来通知它们被观察者发生了变化
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
}
这部分代码很简单,就是在mDataSetObservable.notifyChanged()中遍历所有的观察者,并且调用它们的onChanged方法,从而告知观察者发生了变化。