代码改变世界

观察者模式

2012-11-16 16:13  ...平..淡...  阅读(221)  评论(0编辑  收藏  举报

观察者模式涉及对象:被观察者类、观察者类。(一对多的关系)

观察者模式简单地说:就是当被观察者发生改变时,通知所有观察者。

具体做法是(主要部分分析):

被观察者类中定义setChanged方法,设置改变;定义notifyObservers方法(该方法中会调用观察者的update方法)通知观察者。

观察者类是一个接口,定义update方法。(多个观察者都是实现这个接口)

其实就是在被观察者类中定义一个判断条件,当观察者发生变化时,调用setChanged方法(即将判断条件的值置为true);然后调用Observable类的notifyObservers方法,该方法中调用Observer类的update方法,来实现通知观察者的目的。

最好将被观察者和观察者抽象成接口,然后再创建新的具体被观察者类和观察这类实现这些接口。这样能达到低耦合的效果。

 

观察者模式的结构

观察者(Observer)模式是对象的行为型模式,又叫做发表-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-收听者(Source/Listener)模式或从属者(Dependents)模式。


本模式的类图结构如下:


图1、观察者模式的静态结构可从类图中看清楚。

 

观察者模式在java中的应用:

java中的观察者模式应用
//在java的util包中实现了该设计模式的框架,大部分应用都可以直接用它,当然了你也可以自己实现它,实际上就是一个被观察者的抽象类和一个观察者接口。我们先看一下jdk是如何实现的。被观察者的抽象类java.util.Observable

package java.util;

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);
}

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();
}
}

//当我们自己的被观察者继承这个Observable类是,我们就自动的获取到被观察者的一切条件了。很方便是不是,这也是为什么sun要把Observable放到java.util包中的原因,就是为了方便开发者。

//下面我们再看一下观察者的接口java.util.Observer
package java.util;
public interface Observer {

void update(Observable o, Object arg);

}

//接口中就只有一个方法,update,方法中有两个参数,Observable和一个object,第一个参数就是被观察的对象,而第二个参数就得看业务需求了,需要什么就传进去什么。我们自己的观察者类必须实现这个方法,这样在被观察者调用notifyObservers操作时被观察者所持有的所有观察者都会执行update操作了.

其实java.util.observable设计的也有问题。它是一个“类”,而不是“接口” 。它的实现也有问题,限制了它的使用和复用。

 

1. Java.util.Observable相当与Subject,发出通知时应该先调用setChanged()方法,再调用notifyObservers方法通知观察者。

2. 可以把数据封装成对象传入notifyObservers(Object arg),观察者调用update(Obserable o,Object arg)取出数据,实现推模式。如果调用notifyObservers(),观察者调用update(Obserable o,Object arg)取出Observable,再调用它的get状态方法,实现拉模式。

  

适用性:

1. 当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。

2. 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。

3. 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之,你不希望这些对象是紧密耦合的。

  

优点:

1. 被观察者和观察者间的松耦合。一个被观察者所知道的仅仅是它有一系列观察者,每个都符合抽象的 Observer类的简单接口。被观察者不知道任何一个观察者属于哪一个具体的类。这样目标和观察者之间的耦合是抽象的和最小的。

2. 支持广播通信,主题向所有登记过的观察者发出通知。

  

缺点:

1. 意外的更新。因为一个观察者并不知道其它观察者的存在,它可能对改变被观察者的最终代价一无所知。在被观察者上一个看似无害的的操作可能会引起一系列对观察者以及依赖于这些观察者的那些对象的更新。此外,如果依赖准则的定义或维护不当,常常会引起错误的更新,这种错误通常很难捕捉。

2. 如果一个主题对象有很多直接或间接的观察者对象,将所有的观察者都通知会花费很多时间。

3. 如果对观察者的通知是在另外的线程异步进行的话,要额外注意多线程操作。

 

下面这篇文章不错,也有实例

Java 观察者模式的浅析