您的位置:首页 > 其它

设计模式之观察者模式

2017-09-06 18:45 246 查看
第一次学习观察者模式已经是六七年以前,那个时候只是机械的去理解。也知道JAVA中AWT和SWING中使用了观察者模式。但是没有真正去理解透(当然,现在也可能没有真正理解透,但是比那个时候要好很多)。后面陆续也看过几次,都没有真正去思考观察模式的设计理念。现在有时间了,再重新学习了一遍,发现又领悟到不少,再此记录一下本人的学习心得。欢迎各位大拿,拍砖!!

观察者模式概念

顾名思义,多个观察者关注同一个被观察者。只要被观察者的状态发生变化,所有 观察者都会采取对应的行为。举个例子,校花一般都是有很多追求者的,校花的生日到了,众多追求者会采取行动去取悦校花,都希望打动校花。这其中,校花是被观察者,追求者是观察者,生日是状态变化。

观察者模式中角色

抽象观察者:这里的抽象观察者有可能是接口或者是抽象类。主要是声明了观察者共同的行为,具体的观察者需要去实现这个行为。

具体观察者:实现抽象观察者接口或类中声明的方法,当被观察者状态发生变化时,调用观察者的方法。

抽像主题(被观察者):被观察者也叫主题(subject)。它是所有观察者时刻关注的目标,主题的属性发生变话,会影响到观察者的行为。通常情况下,使用抽象类或者接口表示。(也可以不使用抽象主题)。

具体主题(被观察者):实现抽象主题,具体被观察者所关注的对象。状态真正承载的载体

如何设计观察者

1.在JAVA中使用观察者模式进行编程,需要确定编程的对象。根据观察者模式中的角色,我们可以很容易设计出,观察者接口Observer,具体观察者ObserverImpl,抽象主题Observable,具体观察者ObservableImpl。

2. 观察者需要时刻关注到主题的动态变化,则所有观察者需要将自己注册到一个集中管理的地方,等主题状态发生变化时,能够通知观察者。这就要求主题能够将观察者进行集中管理(采用集合等方式)。反应到JAVA类中时,主题中要提供方法供客户端调用进行增加,删除观察者。

3. 主题类中除了提供集中管理观察者的机制,增加,删除观察者的方法,还应该提供通知观察者的方法。即主题状态发生变化或发生一个事件,能够通知观察者去采取对应的行为。

4. 根据上述1~3步骤分析,大致可以分析出观察者的基本的类图关系。



设计原则

观察者模式中,主题要可以动态管理注册的观察者,即增加或者删除观察者不需要修改主题中的代码,这要求主题中维护的观察者类型是父类型或接口类型。实际操作时,传递具体类型即可,这也符合面向抽象编程,其实就是依赖倒转原则。即依赖抽象而不是依赖具体。

在实际设计过程中,观察者也可以持有被观察者的引用,根据具体情况分析,即观察者接到通知后,调用被观察者的方法处理一些其他业务逻辑。

JDK中使用观察者

在JDK中也提供了对观察者模式的支持。被观察者类Observable,观察者接口Observer。其中被观察者中含有两个属性changed,vetor分别用来表示状态值和管理观察者。观察者接口中定义了一个更新接口。

public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*当被观察者对象发生改变,调用该方法。应用可以调用被观察者的notifyObservers方法通知观察者
* @param   o     the observable object.
* @param   arg   an argument passed to the <code>notifyObservers</code>
*                 method.
*/
void update(Observable o, Object arg);
}


被观察者对象是类Observable,代表被观察者对象。其中有2个属性,chanage和vetor。分别用来代表状态和管理观察者。代码很简单,不作具体分析。

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

/**
*参考notifyObservers(object)
*/
public void notifyObservers() {
notifyObservers(null);
}

/**
* 被观察者对象object状态发生变化,则通知对象object的所有的观察者。然后调用    *       clearChange方法表明,被观察者对象状态不再发生改变。
*/
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
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 u
4000
nregistered Observer will be
*   wrongly notified when it doesn't care
*/
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}

for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}

/**
* Clears the observer list so that this object no longer has any observers.
*/
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();
}
}


通知方式

被观察者通知观察者时,可以直接调用观察者的方法,也可以另外启用一个线程通知每一个观察者,或者采用远程方式通知观察者。



总结

观察者模式在很多框架和容器中都有使用。tomcat容器监听各种事件,zkClient中注册观察者,省却了开发人员反复注册的watcher的麻烦。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  设计模式