《jdk observer设计模式之研究》由会员分享,可在线阅读,更多相关《jdk observer设计模式之研究(4页珍藏版)》请在金锄头文库上搜索。
1、JDK Observer 设计模式之研究目前设计模式的介绍性文章越来越多,但设计模式的研究性文章仍然比较欠缺,这着实让人觉得有点遗憾。本文旨在抛砖引玉,具体分析一下 java 中 jdk 自带的 observer 设计模式(下文如没特别指出,observer 设计模式就意指 java 中 jdk 自带的 observer 设计模式)的实现。1. Observer 设计模式概要Observer 设计模式在 GOF 里属于行为设计模式。JDK 里提供的 observer 设计模式的实现由java.util.Observable 类和 java.util.Observer 接口组成。从名字上可以清楚
2、的看出两者在Observer 设计模式中分别扮演的角色: Observer 是观察者角色,Observable 是被观察目标(subject)角色。Observable 是一个封装 subject 基本功能的类,比如注册 observer(attach 功能) ,注销observer(detatch 功能)等。这些功能是任何一个扮演 observerable 角色的类都需要实现的,从这一点上来讲,JDK 里将这些通用功能专门封装在一个类里,显得合情合理。通常情况下,我们的类只要从 Observerable 类派生就可以称为 observerable 角色类,使用非常简单。2. 使用 obser
3、ver 设计模式存在的困难但我们不得不注意到,在项目实际开发当中,情况往往要复杂得多。java 不支持多继承特性在很多时候是阻碍我们使用 observer 设计模式的绊脚石。比如说,我们设计的一个类已经是某个类的派生类,在这种情况下同时想让它扮演 observerable 角色将变得麻烦。如何实现“多继承”的效果是摆在我们面前的一大难题。下面我们首先分析一下 Observable 类。3. Observable 类 “触发通知”的原理Observable 必须 “有变化”才能触发通知 observer 这一任务,这是它的本质体现。查看源码便可知一二。Observerable 部分源码如下:/省
4、略private boolean changed = false;/省略public void notifyObservers(Object arg) /省略Object arrLocal;synchronized (this) /省略if (!changed)return;arrLocal = obs.toArray();clearChanged();/省略protected synchronized void setChanged() changed = true;protected synchronized void clearChanged() changed = false;正如粗的
5、斜体标注部分所示,在 notifyObservers(Object arg) 方法里 if (!changed)return;语句告诉我们,若 changed 属性值为 false,将直接返回,根本不会触发通知操作。并且我们注意到 changed 属性被初始化为 false,这将意味着如果我们不主动设置 changed属性为 true,将不会有任何变化,也就是说根本起不到“ 通知”作用。因此,设置 changed 属性的值是我们应用 jdk observer 设计模式的关键所在。那么如何才能设置 changed 属性呢?从源码可以看出,唯一的入口是通过 setChanged()。下面我们分析一
6、下 changed 属性及相关的方法 setChanged()和 clearChanged()。4. Observable 类的分析Observable#changed 属性的初始值为 false,这很容易理解,不再详细陈述。细心的读者可能会注意到跟 changed 属性有关的两个方法 setChanged()和 clearChanged(),它们的修饰符都是 protected。想强调的是,是 protected,而不是 public。但这样是否有其必要性和合理性?答案是肯定的。在前面的分析中,我已经提到,setChanged()方法是设置 changed 的唯一入口,它的修饰符定义为 pr
7、otected,就意味着通过定义 Observable 的对象,再设置changed 属性将变得不可能。从这个意义上说,要想应用 observer 设计模式,必须继承Observable 类方可。关于这一点,下文还会提及。但是,为什么不能定义成 public?这似乎难以理解。因为定义成 public,我们不就可以很方便地设置 changed 属性的值吗?为了弄清楚这个问题,我们还是看一下 Observable 里的相关的代码:/省略public void notifyObservers(Object arg) /省略for (int i = arrLocal.length-1; i=0; i-
8、)(Observer)arrLocali).update(this, arg);这段代码表达的意思是说找出所有已注册的 Observer,再逐个进行“通知”,通过调用Observer#update(Observable,Object)方法进行通知。我们看到,update 第一个参数是 this,我们同时还必须注意到,这段代码是 Observable 类里的代码。这就相当于是在一再强调,发出“通知”的,必须是 observable 自己(Observable 类或者其派生类) ,其它任何类都不行。这就意味着我们的 observable 类继承 Observable 类是必要的,因为如果不继承,而
9、采用组合的话,将无法保证能传递好 this。换句话说,采用组合的方式使用 Observable 类,将变得几乎没有任何意义。同时,修饰符定义为 protected,可以确保是在 Obsrvable 里进行触发通知的,不会在其它任何地方进行通知,这显得内敛性很强。如果将 setChanged()修饰符定义为 public,将无法保证正确“传递 this”的硬性要求,这不符合“只有 observalbe 才能直接或间接通知 observer”这一 observable 设计模式的硬性要求。由此我们可见一斑,jdk的很多理念的思想性是多么的强。5. 解决使用 observer 设计模式存在的困难借助
10、 adapter 设计模式(详见本人发表的 adapter 设计模式相关文章)和 java 支持多接口特性基本可以解决“多继承” 问题。基本思想是结合继承/ 实现和组合来达到效果。在上面的分析中,我们已经知道,Observable 类必须继承使用,不能组合使用,因此我们只需要将需扮演成 observerable 角色的类装扮成 adapter 角色,将该类原继承的类装扮成 adaptee 角色即可。示例代码如下:/欲充当 observable 角色的类的原来的代码:public class MyObject extends BaseObject public MyObject() public
11、 void method1()/充当 observable 角色后的代码:public class MyObject extends Observable private BaseObject baseObject = null;public MyObject(BaseObject baseObject) this.baseObject = baseObject;6. 注意事项:如果上例中的 BaseObject 也用到需要传递 “this”的方法,那么上面的组合使用方法将有可能失效。这种情况是最糟糕的情况。此时可以考虑在 BaseObject 类这些“瓶颈” 地方尽量采用接口代替类(包括抽象类)来解决。