浅析JDK Observer设计模式

开发 后端
JDK Observer设计模式的介绍旨在抛砖引玉,从JDK Observer设计模式德介绍和存在的困难等等多角度分析问题,希望对你有所帮助。

Java中JDK自带的JDK Observer设计模式的实现是一个范例,有助于我们在设计模式的思维上有所突破。目前设计模式的介绍性文章越来越多,但设计模式的研究性文章仍然比较欠缺,这着实让人觉得有点遗憾。本文旨在抛砖引玉。

1.JDK Observer设计模式概要

JDK 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.使用JDK Observer设计模式存在的困难

但我们不得不注意到,在项目实际开发当中,情况往往要复杂得多。java不支持多继承特性在很多时候是阻碍我们使用JDK Observer设计模式的绊脚石。比如说,我们设计的一个类已经是某个类的派生类,在这种情况下同时想让它扮演Observerable角色将变得麻烦。如何实现“多继承”的效果是摆在我们面前的一大难题。下面我们首先分析一下Observable类。

3.JDK Observable类“触发通知”的原理

Observable必须“有变化”才能触发通知observer这一任务,这是它的本质体现。查看源码便可知一二。

Observerable部分源码如下:

  1.   //……省略……  
  2.   private boolean changed = false;  
  3.   //……省略……  
  4.   public void notifyObservers(Object arg) {  
  5.   //……省略……  
  6.     Object[] arrLocal;  
  7.     synchronized (this) {  
  8.      //……省略……  
  9.      if (!changed)  
  10.       return;  
  11.       arrLocal = obs.toArray();  
  12.       clearChanged();  
  13.     }  
  14.  
  15.   //……省略……  
  16.   protected synchronized void setChanged() {  
  17.    changed = true;  
  18.   }  
  19.    
  20.   protected synchronized void clearChanged() {  
  21.    changed = false;  
  22.   } 

正如粗的斜体标注部分所示,在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里的相关的代码:

  1.   //……省略……  
  2.   public void notifyObservers(Object arg) {  
  3.   //……省略……  
  4.    for (int i = arrLocal.length-1; i>=0; i--)  
  5.     ((Observer)arrLocal[i]).update(this, arg);  
  6.   } 

    
这段代码表达的意思是说找出所有已注册的Observer,再逐个进行“通知”,通过调用Observer#update(Observable,Object)方法进行通知。我们看到,update 第一个参数是this,我们同时还必须注意到,这段代码是Observable类里的代码。这就相当于是在一再强调,发出“通知”的,必须是observable自己(Observable类或者其派生类),其它任何类都不行。这就意味着我们的observable类继承Observable类是必要的,因为如果不继承,而采用组合的话,将无法保证能传递好this。换句话说,采用组合的方式使用Observable类,将变得几乎没有任何意义。同时,修饰符定义为protected,可以确保是在Obsrvable里进行触发通知的,不会在其它任何地方进行通知,这显得内敛性很强。如果将setChanged()修饰符定义为public,将无法保证正确“传递this”的硬性要求,这不符合“只有observalbe才能直接或间接通知observer”这一observable设计模式的硬性要求。由此我们可见一斑,jdk的很多理念的思想性是多么的强。

5.解决使用observer设计模式存在的困难

借助adapter设计模式(详见本人发表的adapter设计模式相关文章)和java支持多接口特性基本可以解决“多继承”问题。基本思想是结合继承/实现和组合来达到效果。在上面的分析中,我们已经知道,Observable类必须继承使用,不能组合使用,因此我们只需要将需扮演成observerable角色的类装扮成adapter角色,将该类原继承的类装扮成adaptee角色即可。示例代码如下:

  1.   //欲充当observable角色的类的原来的代码:  
  2.   public class MyObject extends BaseObject {  
  3.    public MyObject() {  
  4.     public void method1(){}  
  5.    }  
  6.   }  
  7.  
  8.   //充当observable角色后的代码:  
  9.   public class MyObject extends Observable {  
  10.    private BaseObject baseObject = null;  
  11.     public MyObject(BaseObject baseObject) {  
  12.      this.baseObject = baseObject;  
  13.     }  
  14.   } 

6.JDK Observer注意事项:

如果上例中的BaseObject也用到需要传递“this”的方法,那么上面的组合使用方法将有可能失效。这种情况是最糟糕的情况。此时可以考虑在BaseObject类这些“瓶颈”地方尽量采用接口代替类(包括抽象类)来解决。

那么JDK Observer设计模式就介绍到这里,但是很多的设计模式的思路还是要举一反三慢慢提高。

【编辑推荐】

  1. JDK1.6在LINUX下的安装配置
  2. JDK1.5中新的语言特征浅析
  3. 在JDK7 b50中将实现正则表达式命名捕获组
  4. JDK日志框架介绍及其主要功能浅析
  5. JDK日志框架之自定义日志Handler浅析
责任编辑:仲衡 来源: CSDN博客
相关推荐

2009-08-18 11:03:31

Observer设计模

2009-08-26 10:24:04

C# Observer

2012-01-18 10:47:38

ibmdw

2009-06-29 17:39:31

JSP设计模式

2022-09-04 21:08:50

响应式设计Resize

2024-01-09 09:06:13

2010-07-14 09:01:07

架构设计

2009-04-29 09:06:18

C#设计模式Adapter

2009-07-08 17:59:51

JDK JRE

2009-07-08 14:06:22

ClassLoaderJDK源码

2009-07-09 11:02:37

JDK5.0内置工具

2019-04-24 09:43:46

代码开发工具

2010-11-26 16:17:48

设计模式JDK

2012-08-27 10:52:20

.NET架构观察者模式

2024-08-16 13:59:00

2009-07-08 17:02:11

JDK实现调用拦截器

2009-07-07 15:53:02

JDK日志

2009-07-09 10:28:19

线程池JDK5

2009-07-08 12:53:29

JDK源码Java.lang.B

2009-07-07 15:14:56

JDK日志STAF
点赞
收藏

51CTO技术栈公众号