观察者模式
我们在生活中会遇到这样一些例子,比如你订阅了某人的博客,那么这个人发布博客的时候会将消息推送给你,而且不是只推送你自己一人,只要订阅了该人的博客,那么订阅者都会收到通知,像这样的例子生活中实在是太多了。其实这种操作可以抽象一下,A对象(观察者)对B对象(被观察者)的某种变化高度敏感,需要在B变化的一瞬间做出反应,同时在B对象中维护着所有A的集合。我们在实际编程中称这种模式为观察者模式,有时也称为发布/订阅(Publish/Subscribe)模型。
在JDK的util包中已经帮我们实现了观察者模式,不过我们还是先通过自己写代码来看看观察者到底是怎么回事,自己该如何简单的实现,相信通过自己的简单实现,来理解JDK的观察者模式的实现是十分容易的。
在观察者模式中,首先要有两个角色,观察者与被观察者,这两者拥有的功能是不同的。对于观察者,需要有一个方法来接收被观察者发出的信息(update),而对于被观察者而言,需要在其内部维护一个观察者的列表,用来记录需要通知的观察者(list),所以需要一个添加观察者的方法(addWatcher),同时还要有一个方法可以用来移除观察者(removeWatcher), 最后我们需要一个用来通知所有观察者的方法(notifyWatchers), 一切准备就绪,那么我们来看代码吧。
先定义两个接口,观察者(Watcher)和被观察者(Watched),代码如下:
首先是观察者接口,定义了update方法用来接收通知
/**
* 观察者
* @author mingshan
*
*/
public interface Watcher {
/**
* 用来接收通知
*/
void update();
}
然后是被观察者接口,定义了三个方法:
/**
* 被观察者
* @author mingshan
*
*/
public interface Watched {
/**
* 添加观察者
* @param watcher
*/
void addWatcher(Watcher watcher);
/**
* 移除观察者
* @param watcher
*/
void removeWatcher(Watcher watcher);
/**
* 通知观察者
*/
void notifyWatchers();
}
我们先实现被观察者,重写接口的方法,在其内部维护一个列表,用来存放所有的观察者,当需要通知观察者时,我们就可以调用notifyWatchers方法了,遍历通知所有观察者。
import java.util.ArrayList;
import java.util.List;
public class Thief implements Watched {
private List<Watcher> list = new ArrayList<Watcher>();
@Override
public void addWatcher(Watcher watcher) {
list.add(watcher);
}
@Override
public void removeWatcher(Watcher watcher) {
list.remove(watcher);
}
@Override
public void notifyWatchers() {
for (Watcher watcher: list) {
watcher.update();
}
}
}
我们再实现观察者,重写update方法
public class Police implements Watcher {
@Override
public void update() {
System.out.println("小偷正在偷东西,警察行动!");
}
}
------------------------------
public class Inspector implements Watcher {
@Override
public void update() {
System.out.println("小偷正在偷东西,城管行动!");
}
}
最后我们写个测试类测试一下
import org.junit.Test;
public class ObserverTest {
@Test
public void test() {
Thief thief = new Thief();
Police police = new Police();
Inspector inspector = new Inspector();
thief.addWatcher(police);
thief.addWatcher(inspector);
thief.notifyWatchers();
}
}
以上是我们自己实现的观察者模式,前面说过了在JDK中已经帮我们实现好了观察者模式,那么我们来用一下:
观察者:
/**
* 被观察者 (JDK)
* @author mingshan
*
*/
public class Thief extends Observable {
@Override
public String toString() {
return "我是小偷-_-";
}
public void work() {
System.out.println("ss准备下手偷东西了!");
setChanged();
notifyObservers("-小偷说话:哈哈,你猜我是谁-");
}
}
观察者:
import java.util.Observable;
import java.util.Observer;
public class Police implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println(o + "小偷正在偷东西,警察行动!"+ arg);
}
}
——————————————————————————————————————
import java.util.Observable;
import java.util.Observer;
public class Inspector implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println(o + "小偷正在偷东西,城管行动!" + arg);
}
}
测试类:
import org.junit.Test;
public class ObserverTest {
@Test
public void test() {
Thief thief = new Thief();
Police police = new Police();
Inspector inspector = new Inspector();
thief.addObserver(police);
thief.addObserver(inspector);
thief.work();
}
}
在Observable类源码中,我们可以看到有个changed的布尔值成员变量,用来标志当前对象是否已经被改变,所有在通知观察者之前我们将其置为true
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
/** Construct an Observable with zero Observers. */
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);
}
/**
* 通知所有的观察者
*/
public void notifyObservers() {
notifyObservers(null);
}
/**
* 通知所有的观察者(遍历),同时可以将一些信息传递给观察者,实际上是调用观察** 者的update方法
*/
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
/**
* 删除观察者
*/
public synchronized void deleteObservers() {
obs.removeAllElements();
}
/**
* 将判断当前对象是否改变的flag设置为true
*/
protected synchronized void setChanged() {
changed = true;
}
/**
* 将判断当前对象是否改变的flag设置为false
*/
protected synchronized void clearChanged() {
changed = false;
}
/**
* 判断当前对象是否改变
*
*/
public synchronized boolean hasChanged() {
return changed;
}
/**
* 统计观察者数量
*/
public synchronized int countObservers() {
return obs.size();
}
}