一、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. 【转】每天一个linux命令(43):killall命令

    原文网址:http://www.cnblogs.com/peida/archive/2012/12/21/2827366.html Linux系统中的killall命令用于杀死指定名字的进程(kill ...

  2. Linux elasticsearch 安装 遇到的问题

    备注:我的 Linux 测试机  是2G 内存的 ,估计内存小于 我的内存肯定会出这个问题 .(安装的最新版6.3.2) 1.  下载文件  解压 2 .试着 运行 bin 下面的 elasticse ...

  3. asp.net core控制台项目运行

    cmd中进入项目生成的dll目录下 运行命令: start dotnet xxx.dll

  4. ML(5):KNN算法

    K近邻算法,即K-Nearest Neighbor algorithm,简称KNN算法,可以简单的理解为由那离自己最近的K个点来投票决定待分类数据归为哪一类.这个算法是机器学习里面一个比较经典的算法, ...

  5. webSocket支持的浏览器

  6. 360 杀毒几K每秒的IO读取,SO MAD

    在没有用360杀毒扫描的状态下,从任务管理器中查看,居然有几K每秒的IO读取 . 好卡,直接卸载.

  7. TS流的解析

    个字节不一定都是有效数据,有一些可能为填充数据). 工作形式: 因为在TS流里可以填入很多种东西,所以有必要有一种机制来确定怎么来标识这些数据.制定TS流标准的机构就规定了一些数据结构来定义.比如: ...

  8. 关于UC、火狐、谷歌浏览器屏蔽布局中广告的解决办法

     关于UC浏览器屏蔽了广西人才网的名企.品牌.热点的logo,是因为当成广告过滤掉了,以后div的class和id不能以“ad”开头.这可能只是其中一个规则,adxxxx是可以的,不能是adXxxx, ...

  9. 阿里云内网和公网NTP服务器和其他互联网基础服务时间同步服务器

    阿里云为云服务器ECS提供了内网NTP服务器,对于阿里云以外的设备,阿里云同时提供了 公网NTP服务器,供互联网上的设备使用. 内网和公网NTP服务器 以下为阿里云提供的内网和公网NTP服务器列表. ...

  10. Unreal Engine 4(虚幻UE4)GameplayAbilities 插件入门教程(六)GameplayEffect的级别设置

    本节的内容不难,权当是复习.如果没有完成前面的教程,请前往学习. 第一步:用一个csv文件表示级别数据,下图中的Hurt随级别1~7表示其损伤值在1~7级别时分别是-7,-14,-20等.写好之后关闭 ...