一、简介

观察者设计模式有如下四个角色

  • 抽象主题角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类或接口来实现,也可以使用非抽象类来实现。
  • 具体主题角色:在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。
  • 抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
  • 具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。通常用一个子类实现。

  观察者设计模式类图如下:

二、java JDK中对观察者的支持
  java JDK中提供了Observer 与 Observable两个类。Observer类可以看作是抽象观察者角色,而Observable是抽象主题角色。

  1、Objserver

    Objserver 是个接口,代码如下:

  1. public interface Observer {
  2. /**
  3. * 该方法当主题对象发生改变的时候被调用. An
  4. * 一个应用调用主题对象的notifyObservers方法来application calls an <tt>Observable</tt> object's
  5. * <code>notifyObservers</code> method to have all the object's
  6. * observers notified of the change.
  7. *
  8. * @param o the observable object.
  9. * @param arg an argument passed to the <code>notifyObservers</code>
  10. * method.
  11. */
  12. void update(Observable o, Object arg);
  13. }

  它只提供了一个update,让子类去实现。当主题对象发生改变的时候,就会调用观察者对象的update方法,从而达到观察者发生改变的目的。

  2、Observable

    Observable是个类,代码如下:

  1. public class Observable {
  2. private boolean changed = false;
  3. private Vector obs;//用于存放观察者对象的引用
  4.  
  5. public Observable() {
  6. obs = new Vector();
  7. }
  8.  
  9. //添加一个观察者
  10. public synchronized void addObserver(Observer o) {
  11. if (o == null)
  12. throw new NullPointerException();
  13. if (!obs.contains(o)) {
  14. obs.addElement(o);
  15. }
  16. }
  17.  
  18. //移除一个观察者
  19. public synchronized void deleteObserver(Observer o) {
  20. obs.removeElement(o);
  21. }
  22.  
  23. //通知所有观察者
  24. public void notifyObservers() {
  25. notifyObservers(null);
  26. }
  27.  
  28. //通知指定的观察者
  29. public void notifyObservers(Object arg) {
  30. Object[] arrLocal;
  31.  
  32. synchronized (this) {
  33. if (!changed)//当状态没有发生改变的时候,直接返回
  34. return;
  35. arrLocal = obs.toArray();
  36. clearChanged();
  37. }
  38. //通知并调用观察者的update方法
  39. for (int i = arrLocal.length-1; i>=0; i--)
  40. ((Observer)arrLocal[i]).update(this, arg);
  41. }
  42.  
  43. //移除所有观察者
  44. public synchronized void deleteObservers() {
  45. obs.removeAllElements();
  46. }
  47.  
  48. //设置状态改变
  49. protected synchronized void setChanged() {
  50. changed = true;
  51. }
  52.  
  53. //重置状态
  54. protected synchronized void clearChanged() {
  55. changed = false;
  56. }
  57.  
  58. //判断是否状态是否发生改变
  59. public synchronized boolean hasChanged() {
  60. return changed;
  61. }
  62.  
  63. 返回观察者的个数
  64. public synchronized int countObservers() {
  65. return obs.size();
  66. }
  67. }

  从代码可以看出,我们可以让具体主题对象继承Observable类,具体观察者对象实现Observer接口并实现update方法。调用的时候只需要实例化具体主题对象与具体观察者对象,然后将具体观察者对象添加到具体主题对象中的obs(Vector)列表。当具体主题对象的状态发生该变时,调用观察者对象的update方法(这里状态发生该变指的是调用主题对象的某个方法,该方法里面有对具体观察者对象的update方法的调用)。

三、实例

  具体观察者对象

  1. 具体主题对象
  2. package com.observer;
  3.  
  4. import java.util.Observable;
  5. /**
  6. * 具体主题对象
  7. *
  8. */
  9. public class ConcreteSubject extends Observable {
  10.  
  11. private String info;
  12.  
  13. public String getInfo() {
  14. return info;
  15. }
  16.  
  17. public void setInfo(String info) {
  18. this.info = info;
  19. }
  20.  
  21. public void doSomething(String str) {
  22. System.out.println("subject: " + str);
  23. setInfo(str);
  24. setChanged();//改变主题对象的状态,这里如果不改变它的状态,则不会对观察者对象调用update方法
  25. // notifyObservers();//也可以不传递参数
  26. notifyObservers("subject is changed");//这里传递的参数是观察者对象中update方法参数列表中的第二个参数
  27. }
  28. }

  具体观察者对象

  1. package com.observer;
  2.  
  3. import java.util.Observable;
  4. import java.util.Observer;
  5. /**
  6. * 具体观察者对象
  7. *
  8. */
  9. public class ConcreteObserver implements Observer {
  10.  
  11. /**
  12. * @param subject 具体主题对象
  13. * @param arg notifyObservers(String str) 传递的参数
  14. */
  15. public void update(Observable o, Object arg) {
  16. System.out.println(arg);
  17.  
  18. ConcreteSubject subject = (ConcreteSubject)o;
  19. System.out.println("observer: " + subject.getInfo());
  20. }
  21. } 

  调用代码:

  1. package com.observer;
  2.  
  3. import java.util.Observer;
  4.  
  5. public class Test {
  6. public static void main(String[] args) {
  7. //观察者对象
  8. Observer observer = new ConcreteObserver();
  9. Observer observer2 = new ConcreteObserver();
  10. Observer observer3 = new ConcreteObserver();
  11.  
  12. //主体对象
  13. ConcreteSubject observable = new ConcreteSubject();
  14.  
  15. //观察者加入主题对象汇总的观察者列表
  16. observable.addObserver(observer);
  17. observable.addObserver(observer2);
  18. observable.addObserver(observer3);
  19.  
  20. //主体对象发生改变
  21. observable.doSomething("happy");
  22. observable.doSomething("sad");
  23. }
  24. }

                                                 

观察者模式--java jdk中提供的支持的更多相关文章

  1. 使用jdk中提供的排序方式

    package com.bjpowernode.t01; import java.util.Arrays; /** * 使用jdk中提供的排序方式 * */public class TestArray ...

  2. 关于Java JDK中 URLDecoder.decode 方法

    java.net.URLDecoder.decode 在项目中碰到了个比较奇怪的问题,就是我在本地使用java.net.URLDecoder.decode(ruleName)方法解码,没有问题,本地的 ...

  3. java jdk中安装证书的步骤

    需要注意的是:导入证书时,请确认导入的JDK为当前程序运行所用的JDK,且路径是jdk目录下的jre目录路径,非与jdk同级的jre目录 首先你可以把需要导入的证书放在keytool的同级目录下,然后 ...

  4. java jdk 中HashMap的源码解读

    HashMap是我们在日常写代码时最常用到的一个数据结构,它为我们提供key-value形式的数据存储.同时,它的查询,插入效率都非常高. 在之前的排序算法总结里面里,我大致学习了HashMap的实现 ...

  5. [JAVA]SpringBoot中让接口支持跨域

    官方原文:https://spring.io/blog/2015/06/08/cors-support-in-spring-framework ===抽空翻译 最简单办法:在方法上增加注解: @Cro ...

  6. Eclipse建立Java工程中的三个JRE选项的区别(Use an execution environment JRE,Use a project specific JRE,Use default JRE)

    本博客部分转载自: http://blog.csdn.net/wdjhzw/article/details/42086615  这篇博客写的非常好,很用心. 一.首先看新建Java Project时候 ...

  7. JDK中的Timer和TimerTask详解(zhuan)

    http://www.cnblogs.com/lingiu/p/3782813.html ************************************************** 目录结构 ...

  8. Java 7 中 NIO.2 的使用——第一节 Path 类的使用

    路径隶属于文件系统,实际上它是存储和组织媒体文件的格式,通常在一块或多块硬盘设备上,以便于非常容易地检索.文件系统可以通过  java.nio.file.FileSystems 这个final 类来访 ...

  9. Java JDK 1.7 和 JDK 1.8 新特性

    0 引言 本文主要介绍 Java JDK 中 1.7 和 1.8 的新特性. 1 JDK 1.7 新特性 1. switch可以接受String类型: public class Switch { pu ...

随机推荐

  1. POI中getLastRowNum() 和getLastCellNum()的区别 hssfSheet.getLastRowNum();//最后一行行标,比行数小1 hssfSheet.getRow(k).getLastCellNum();//获取列数,比最后一列列标大1

    hssfSheet.getLastRowNum();//最后一行行标,比行数小1 hssfSheet.getRow(k).getLastCellNum();//获取列数,比最后一列列标大1

  2. List<?>和List<T>的区别?

    出自:https://www.zhihu.com/question/31429113

  3. 自己动手搞定支付宝手机网站支付接口 FOR ECShop

    支付宝WAP网站版本的支付接口网上整合的比较少,看到很多网站在卖,顿觉无语. 主要是得自己查看支付宝官方提供的SDK中的开发文档. 支付宝sdk下载地址:https://doc.open.alipay ...

  4. ahjesus 创建msdn一样的帮助文档

    转载自http://www.cnblogs.com/DotNetNuke/archive/2009/04/23/1441899.html 使用SandCastle创建.Net帮助文档 Sandcast ...

  5. Cookies简介和使用

    Cookie public class javax.servlet.http.Cookie  1作用(1)Cookie能使站点跟踪特定访问者的访问次数.最后访问时间和访问者进入站点的路径(2)Cook ...

  6. Virtual Environments for mac

    A Virtual Environment is a tool to keep the dependencies required by different projects in separate ...

  7. 奇怪的float

    我在项目的实践中遇到了这样的一个问题 <div class="main"> <p>aaaa</p> <p>bbbb</p> ...

  8. javascript获取url信息的常见方法

    先以"http://www.cnblogs.com/wuxibolgs329/p/6188619.html#flag?test=12345"为例,然后获得它的各个组成部分. 1.获 ...

  9. XML的约束(dtd)

    DTD(Document Type Definition),文档类型定义,DTD文件应使用UTF-8或Unicode   1.XML中有多少个元素,就在dtd文件中写几个 <!ELEMENT&g ...

  10. IOS6学习笔记(三)

    1.ARC空声明变量 使用ARC的另一个优势是所有未初始化的变量默认都是“空值化”的.这意味着像下面这样的声明使用ARC编译后指向的是空值(nil): NSObject *myObject1,*myO ...