在编程的很多时候,我们会用到观察者模式,只不过我们不曾注意到。 比如说,图形程序的时候,Listener 等等等.....很多场景大量的应用了观察者模式。
那么现在就让我们来具体学习下吧。
举一个生活中的例子。
当我们在烧水的时候,水就是被观察的对象,人就是被观察者。
当水烧开后,人立刻去吧电源拔掉了。
这就是生活中的一个典型的观察者模式。
那么好,我们来具体看一下代码实现。
这里笔者写了一个demo。来说明,代码上的注释已经足够详细了。
package hello;
import java.util.ArrayList;
import java.util.List;
/**
* 抽象出来的Observer接口
*/
interface Observer
{
/**
* 观察者要实现的对象
*/
void update();
}
/**
* 抽象出来的被观察的对象
*/
abstract class Observable
{
/**
* 被观察者内部引用多个观察者
*/
List<Observer> observers = new ArrayList<>();
String status = "";
void notifyObserver()
{
for(int i = 0 ; i < observers.size() ; i++)
{
observers.get( i ).update();
}
}
}
/**
* 当水烧开,人立即去将电源拔掉。
* 这里水就是被观察的对象,人是观察者
*/
class Water extends Observable
{
void addObserver(Observer observer)
{
this.observers.add( observer );
}
void removeAllObserver()
{
this.observers.clear();
}
void removeObserver(Observer observer)
{
this.observers.remove( observer );
}
void setStatus(String status)
{
this.status = status;
notifyObserver();
}
}
/**
* 具体观察者的实现
*/
class Person implements Observer
{
@Override
public void update()
{
System.out.println( "人吧插头拔掉了" );
}
}
public class Main
{
public static void main(String[] args)
{
Person person = new Person();
Water water = new Water();
//增加了观察者
water.addObserver( person );
water.setStatus( "水开了" );
}
}
当然,被观察的对象里应该有一个成员变量去标示这个状态是否发生。
我们先点到 java.util.Observer接口来看,可以看到里面只有一个方法 update(Observable o ,Object arg);
这里跟笔者自己写的update方法相差无几。
package java.util;
public class Observable {
private boolean changed = false;
/**
*可以看到,这里也维护了一群观察者。只不过jdk用的Vector,笔者用的是List
*/
private Vector<Observer> 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);
}
//
public void notifyObservers() {
notifyObservers(null);
}
//通知所有观察者
public void notifyObservers(Object arg) {
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();
}
//改变标志量
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的实现跟笔者写的demo相差无几,只不过jdk的实现做了线程同步