一、Observer模式的意图:

在对象的内部状态发生变化时,自动通知外部对象进行响应。

二、Observer模式的构成:

·被观察者:内部状态有可能被改变,而且又需要通知外部的对象

·观察者:需要对内部状态的改变做出响应的对象

三、Observer模式的Java实现:

Java的API中已经为我们提供了Observer模式的实现。具体由java.util.Observable类和java.util.Observer接口完成。

前者有两个重要的方法:

·setChanged:设置内部状态为已改变

·notifyObservers(Object obj):通知观察者所发生的改变,参数obj是一些改变的信息

后者有一个核心方法:

·update(Object obj):相应被观察者的改变,其中obj就是被观察者传递过来的信息,该方法会在notifyObservers被调用时自动调用。

下面是Observer模式的实现过程:

·创建一个被观察者,继承java.util.Observable

·创建一个观察者,实现java.util.Observer接口

· 注册观察着,调用addObserver(Observer observer)

·在被观察者改变对象内部状态的地方,调用setChanged()方法,然后调用notifyObservers(Object)方法,通知被观察者

·在观察者的update(Object)方法中,对改变做出响应。

四、Observer模式的好处:

1.Observer模式的优点:

·被观察者只需要知道谁在观察它,无需知道具体的观察细节

·被观察者一旦发生变化,只需要通过广播的方式告知观察者,至于消息如何到达则不需知道。这样的话无疑消除了被观察者和观察者之间通信的硬编码

·当一个被观察者同时被多个观察着观察时,观察者可以只选择自己感兴趣的事件,而忽略其它的事件
   
                      ·多个观察者组合起来可以形成一个观察链,如果一旦需要回滚多个操作,此时观察链可以发挥作用

·观察者可以实时对被观察对象的变化做出响应,例如自动告警、中断运行等

2.运用Observer模式可以

·屏蔽线程间的通信机制:例如两个线程之间,主线程可以作为观察者,执行线程是被观察者。彼此之间只知道对方存在,但不知道之间通信的细节

·消除硬编码:如果没有Observer模式,则只能采用回调的模式,或者在代码中显示地调用观察者

·优化异常机制:特别适合在异常发生时向顶层监控,减少try-catch代码量

代码:

  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. */
  11. public synchronized void addObserver(Observer o) {
  12. if (o == null)
  13. throw new NullPointerException();
  14. if (!obs.contains(o)) {
  15. obs.addElement(o);
  16. }
  17. }
  18. /**
  19. * 删除一个观察者
  20. */
  21. public synchronized void deleteObserver(Observer o) {
  22. obs.removeElement(o);
  23. }
  24. /**
  25. * 通知操作,即被观察者发生变化,通知对应的观察者进行事先设定的操作,不传参数的通知方法
  26. */
  27. public void notifyObservers() {
  28. notifyObservers(null);
  29. }
  30. /**
  31. * 与上面的那个通知方法不同的是,这个方法接受一个参数,这个参数一直传到观察者里,以供观察者使用
  32. */
  33. public void notifyObservers(Object arg) {
  34. Object[] arrLocal;
  35. synchronized (this) {
  36. if (!changed)
  37. return;
  38. arrLocal = obs.toArray();
  39. clearChanged();
  40. }
  41. for (int i = arrLocal.length-1; i>=0; i--)
  42. ((Observer)arrLocal[i]).update(this, arg);
  43. }
  44. }
  45. public interface Observer {
  46. /**
  47. * This method is called whenever the observed object is changed. An
  48. * application calls an <tt>Observable</tt> object's
  49. * <code>notifyObservers</code> method to have all the object's
  50. * observers notified of the change.
  51. *
  52. * @param   o     the observable object.
  53. * @param   arg   an argument passed to the <code>notifyObservers</code>
  54. *                 method.
  55. */
  56. void update(Observable o, Object arg);
  57. }
  58. }
  59. public class MailObserver implements Observer{
  60. /**
  61. * 这个类取名为MailObserver,顾名思义,她是一个用来发送邮件的观察者
  62. */
  63. public void update(Observable o, Object arg) {
  64. System.out.println("发送邮件的观察者已经被执行");
  65. }
  66. }
  67. public class JMSObserver implements Observer{
  68. public void update(Observable o, Object arg) {
  69. System.out.println("发送消息给jms服务器的观察者已经被执行");
  70. }
  71. }
  72. public class Subject extends Observable{
  73. /**
  74. * 业务方法,一旦执行某个操作,则通知观察者
  75. */
  76. public void doBusiness(){
  77. if (true) {
  78. super.setChanged();
  79. }
  80. notifyObservers("现在还没有的参数");
  81. }
  82. public static void main(String [] args) {
  83. //创建一个被观察者
  84. Subject subject = new Subject();
  85. //创建两个观察者
  86. Observer mailObserver = new MailObserver();
  87. Observer jmsObserver = new JMSObserver();
  88. //把两个观察者加到被观察者列表中
  89. subject.addObserver(mailObserver);
  90. subject.addObserver(jmsObserver);
  91. //执行业务操作
  92. subject.doBusiness();
  93. }
  94. }

在spring中使用观察者模式的方法如下

<bean id="mailObserver" class="MailObserver"/>    
      
  <bean id="jmsObserver" class="JMSObserver"/>    
      
  <bean id="subjectTarget" class="Subject"/>    
      
  <bean id="subject"   
         class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">    
         <property name="targetObject"><ref local="subjectTarget"/></property>    
         <property name="targetMethod"><value>addObserver</value></property>    
         <property name="arguments">    
           <list>    
              <ref bean="mailObserver"/>    
              <ref bean="jmsObserver"/>    
           </list>    
        </property>    
  </bean>   
观察者模式的效果有以下几个优点:

(1)观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体现察者聚集,每一个具体现察者都符合一个抽象观察者 的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象 化层次。

(2)观察者模式支持广播通信。被观察者会向所有的登记过的观察者发出通知。

观察者模式有下面的一些缺点:

(1)如果一个被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

(2)如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察考模式时要特别注意这一点。

(3)如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。

(4)虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的

java 观察者模式 与spring配置的更多相关文章

  1. 开涛spring3(12.4) - 零配置 之 12.4 基于Java类定义Bean配置元数据

    12.4  基于Java类定义Bean配置元数据 12.4.1  概述 基于Java类定义Bean配置元数据,其实就是通过Java类定义Spring配置元数据,且直接消除XML配置文件. 基于Java ...

  2. Spring配置c3p0数据源时出错报:java.lang.NoClassDefFoundError: com/mchange/v2/ser/Indirector

    今天在使用Spring配置c3p0数据源时,使用的数据库是mysql,服务器是tomcat,运行时报了一个 java.lang.NoClassDefFoundError: com/mchange/v2 ...

  3. 用Spring提高java观察者模式灵活性

    在上篇博客 用java观察者模式解耦经典三层架构 的最后,用了一个Client类把Listener的实现类注冊到了LoginEventSource类中,假设须要加入�新的逻辑,加入�新的listene ...

  4. 基于纯Java代码的Spring容器和Web容器零配置的思考和实现(3) - 使用配置

    经过<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(1) - 数据源与事务管理>和<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(2) - ...

  5. Spring基础篇——通过Java注解和XML配置装配bean

    自动化装配的确有很大的便利性,但是却并不能适用在所有的应用场景,比如需要装配的组件类不是由自己的应用程序维护,而是引用了第三方的类库,这个时候自动装配便无法实现,Spring对此也提供了相应的解决方案 ...

  6. java多线程、线程池及Spring配置线程池详解

    1.java中为什么要使用多线程使用多线程,可以把一些大任务分解成多个小任务来执行,多个小任务之间互不影像,同时进行,这样,充分利用了cpu资源.2.java中简单的实现多线程的方式 继承Thread ...

  7. java 线程池(ExecutorService与Spring配置threadPoolTaskExecutor)

    一.java ExecutorService实现 创建ExecutorService变量private ExecutorService executor = null 2.执行对应任务时,首先生成线程 ...

  8. spring 配置 Java配置类装配bean

    https://www.cnblogs.com/chenbenbuyi/p/8457700.html 自动化装配的确有很大的便利性,但是却并不能适用在所有的应用场景,比如需要装配的组件类不是由自己的应 ...

  9. 【Java Web开发学习】Spring配置数据源

    Spring配置数据源 转载:https://www.cnblogs.com/yangchongxing/p/10027495.html =============================== ...

随机推荐

  1. k最邻近算法——加权kNN

    加权kNN 上篇文章中提到为每个点的距离增加一个权重,使得距离近的点可以得到更大的权重,在此描述如何加权. 反函数 该方法最简单的形式是返回距离的倒数,比如距离d,权重1/d.有时候,完全一样或非常接 ...

  2. revit API 生成墙图元

    由于Revit的版本问题,在网上找的生成墙图元的代码,在我机器上的Revit 2016中编译不能通过,通过多次调试,终于找到在revit 2016中使用API生成墙图元的代码,现在贴出来. 下面的代码 ...

  3. Nginx 整合 FastDFS 实现文件服务器

    原文地址:Nginx 整合 FastDFS 实现文件服务器 博客地址:http://www.extlight.com 一.前言 本篇衔接<FastDFS 环境搭建>内容进行讲解,上篇文章我 ...

  4. git 不能拉取时,检查是不是被杀毒软件给干掉了

    我这儿是 \Git\bin\sh.exe 被干掉了. 添加排除,并从隔离区中还原.

  5. 小峰servlet/jsp(4)EL表达式

    一.EL表达式内置对象: 二.EL表达式访问4种范围属性: 寻找值的顺序: page-->request-->session-->application; 三.EL表达式接收请求参数 ...

  6. [转]Excel.dll 导出Excel控制

    Excel.dll 导出Excel控制 2010-06-12 11:26 2932人阅读 评论(2) 收藏 举报 excelmicrosoftstring产品服务器google 最近做了个导出Exce ...

  7. (转)RRU交织冗余在LTE-R组网中的应用研究

    RRU交织冗余在LTE-R组网中的应用研究 王 芳1,2 庞萌萌1,2 (1.北京全路通信信号研究设计院集团有限公司,北京 100070; 2.北京市高速铁路运行控制系统工程技术研究中心,北京 100 ...

  8. ie下 iframe在页面中显示白色背景 如何去掉的问题

    ie下:

  9. Delphi Webbrowser使用方法详解(二)

    delphi如何用webbrowser模拟登录网站? 我们就以如何登录博客园来做示例: 1.要登入一个网站,首先要获取网页的源代码,我们可以通过网页菜单--查看--查看源代码来获取. 2.我们找到登录 ...

  10. Hive基础之Hive环境搭建

    Hive默认元数据信息存储在Derby里,Derby内置的关系型数据库.单Session的(只支持单客户端连接,两个客户端连接过去会报错): Hive支持将元数据存储在关系型数据库中,比如:Mysql ...