JDK Observer设计模式研究
副标题#e#
今朝设计模式的先容性文章越来越多,但设计模式的研究性文章仍然较量欠缺,这着实让人以为有点遗憾。本文旨在抛砖引玉,详细阐明一下java中jdk自带的observer设计模式(下文如没出格指出,observer设计模式就意指java中jdk自带的observer设计模式)的实现。
1.Observer设计模式提要
Observer设计模式在GOF里属于行为设计模式。JDK里提供的observer设计模式的实现由java.util.Observable类和java.util.Observer接口构成。从名字上可以清楚的看出两者在Observer 设计模式中别离饰演的脚色:Observer是调查者脚色,Observable是被调查方针(subject)脚色。
Observable是一个封装subject根基成果的类,好比注册observer(attach成果),注销observer(detatch成果)等。这些成果是任何一个饰演observerable脚色的类都需要实现的,从这一点上来讲,JDK里将这些通用成果专门封装在一个类里,显得合情公道。凡是环境下,我们的类只要从Observerable类派生就可以称为observerable脚色类,利用很是简朴。
2.利用observer设计模式存在的坚苦
但我们不得不留意到,在项目实际开拓傍边,环境往往要巨大得多。java不支持多担任特性在许多时候是阻碍我们利用observer设计模式的绊脚石。好比说,我们设计的一个类已经是某个类的派生类,在这种环境下同时想让它饰演observerable脚色将变得贫苦。如何实现“多担任”的结果是摆在我们眼前的一浩劫题。下面我们首先阐明一下Observable类。
3.Observable类“触发通知”的道理
Observable必需“有变革”才气触发通知observer这一任务,这是它的本质浮现。查察源码便可知一二。Observerable部门源码如下:
//……省略……
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;
}
正如粗的斜体标注部门所示,在notifyObservers(Object arg) 要领里if (!changed) return;语句汇报我们,若changed属性值为false,将直接返回,基础不会触发通知操纵。而且我们留意到changed 属性被初始化为false,这将意味着假如我们不主动配置changed属性为true,将不会有任何变革,也就是说基础起不到“通知”浸染。因此,配置changed属性的值是我们应用jdk observer 设计模式的要害地址。那么如何才气配置changed属性呢?从源码可以看出,独一的进口是通过setChanged()。下面我们阐明一下changed属性及相关的要领setChanged()和clearChanged()。
4.Observable类的阐明
Observable#changed属性的初始值为false,这很容易领略,不再具体告诉。细心的读者大概会留意到跟changed属性有关的两个要领setChanged()和clearChanged(),它们的修饰符都是protected。想强调的是,是protected,而不是public。但这样是否有其须要性和公道性?谜底是必定的。在前面的阐明中,我已经提到,setChanged()要领是配置changed的独一进口,它的修饰符界说为protected,就意味着通过界说Observable的工具,再配置changed属性将变得不行能。从这个意义上说,要想应用observer设计模式,必需担任Observable类方可。关于这一点,下文还会提及。可是,为什么不能界说成public?这好像难以领略。因为界说成public,我们不就可以很利便地配置changed属性的值吗?为了弄清楚这个问题,我们照旧看一下Observable里的相关的代码:
//……省略……
public void notifyObservers(Object arg) {
//……省略……
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
这段代码表达的意思是说找出所有已注册的Observer,再逐个举办“通知”,通过挪用Observer#update(Observable,Object)要领举办通知。我们看到,update 第一个参数是this,我们同时还必需留意到,这段代码是Observable类里的代码。这就相当于是在一再强调,发出“通知”的,必需是observable本身(Observable类可能其派生类),其它任何类都不可。这就意味着我们的observable类担任Observable类是须要的,因为假如不担任,而回收组合的话,将无法担保能通报好this。换句话说,回收组合的方法利用Observable类,将变得险些没有任何意义。同时,修饰符界说为protected,可以确保是在Obsrvable里举办触发通知的,不会在其它任那里所举办通知,这显得内敛性很强。假如将setChanged()修饰符界说为public,将无法担保正确“通报this”的硬性要求,这不切合“只有observalbe才气直接或间接通知observer”这一observable设计模式的硬性要求。由此我们可见一斑,jdk的许多理念的思想性是何等的强。
#p#副标题#e#
5.办理利用observer设计模式存在的坚苦
#p#分页标题#e#
借助adapter设计模式(详见本人颁发的adapter设计模式相关文章)和java支持多接口特性根基可以办理“多担任”问题。根基思想是团结担任/实现和组合来到达结果。在上面的阐明中,我们已经知道,Observable类必需担任利用,不能组合利用,因此我们只需要将需饰演成observerable脚色的类装扮成adapter脚色,将该类原担任的类装扮成adaptee脚色即可。示例代码如下:
//欲充当observable脚色的类的本来的代码:
public class MyObject extends BaseObject {
public MyObject() {
public void method1(){}
}
}
//充当observable脚色后的代码:
public class MyObject extends Observable {
private BaseObject baseObject = null;
public MyObject(BaseObject baseObject) {
this.baseObject = baseObject;
}
}
6.留意事项:
假如上例中的BaseObject也用到需要通报“this”的要领,那么上面的组合利用要领将有大概失效。这种环境是最糟糕的环境。此时可以思量在BaseObject类这些“瓶颈”处所只管回收接口取代类(包罗抽象类)来办理。