对于观察者模式,我们知道它是设计模式的一种, 利用接口将数据和使用数据的对象进行解耦。 如果你是个老鸟的话,就知道 Java的 util的 Observer接口是实现观察者模式的关键。 如果你是初学者的话对于观察者模式也应该不陌生, 比如Android的BaseAdapter使用的就是观察者模式。
首先当然是实现 Observer接口,
public interface Observer {
void update(Observable o, Object arg);
}
`
举个例子,现在有个图书管理系统,学生可以跟图书馆借书, 这里假设有两个类, Student 和 Library, 从观察者角度来说的话,Student 是观察者,那么它需要实现接口
public class Student implements Observer {
void update(Observable o, Object arg) {
borrowBooks();
}
}
`
接下来是 Library,它主要负责管理图书,当库存图书发生更改的时候,通知学生可以来借书了。
public class Library extends Observable {
ArrayList<Book> books = ....;
public void returnBook(Book book) {
this.books.add(book);
this.notifyObservers();
}
public void borrowBook(Book book) {
this.books.remove(book);
this.notifyObservers();
}
}
`
这是个非常简单的例子,在客户端代码里只要往Library里添加观察者,就可以在每次数据发生更改时通过 update()方法通知到 Student实例。
....
Library library = new Library();
Student hanzo = new Student("hanzo");
Student genji = new Student("genji");
library.addObserver(hanzo);
library.addObserver(genji);
`
在并发情况下,观察者模式变的有点复杂起来。 比如上面的例子,图书馆每天都在不停的增加新的学生,也有学生在毕业离开, 也就是说当我们在通知学生的时候,手上的学生名单是在不停变化的,那么就得对它加锁。 另外一个,我们希望只有在数据发生变化的时候才通知学生, 意味着即使有人调用了 notify,但是数据没有变化的情况下,我们不会通知观察者。 对于这两个问题,源码是这么处理的,
public void notifyObservers(Object arg) {
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 (!hasChanged())
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
`
它的逻辑是这样的 · 首先检查是否数据有发生变化 · 从已经注册的观察者列表中复制一份新数据 · 重置数据变化的 boolean 值 · 对这个过程加锁 · 逐个通知观察者
可以看出来观察者在极限情况下是有可能出现bug, 也就是注释中说的 · 刚刚加入的观察者收不到通知 · 刚刚移除的观察者还收到通知
对于观察者模式需要注意的也就是这么多了, 在开发中观察者可以很好的解耦UI和数据层,这对于代码结构来说很有帮助。