一、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. PHP写的手机端网站,可以打包成app吗,怎么打包?

    8:13:36 沐歌-重庆 2018/1/19 8:13:36 PHP写的手机端网站,可以打包成app吗,怎么打包 风太大-淮安 2018/1/19 8:14:58 变色龙 沐歌-重庆 一般用什么打包 ...

  2. tomcat源码阅读之StandardContext

    Context实例表示一个具体的web应用程序,其中包含一个或者多个Wrapper实例,每个Wrapper表示一个具体的servlet定义.StandardContext类是Context接口的标准实 ...

  3. 【转】每天一个linux命令(7):mv命令

    原文网址:http://www.cnblogs.com/peida/archive/2012/10/27/2743022.html mv命令是move的缩写,可以用来移动文件或者将文件改名(move  ...

  4. MVC ASP.NET MVC各个版本的区别 (转)

    Net Framework4.5是不支持安装在window server 2003上,如非装请用net framework4.0; MVC1.0 publsh time:2008 IDEV:VS200 ...

  5. LOJ 2542 「PKUWC2018」随机游走 ——树上高斯消元(期望DP)+最值反演+fmt

    题目:https://loj.ac/problem/2542 可以最值反演.注意 min 不是独立地算从根走到每个点的最小值,在点集里取 min ,而是整体来看,“从根开始走到点集中的任意一个点就停下 ...

  6. 打开Visual Studio 2012的解决方案 连接 Dynamics CRM 2011 的Connect to Dynamics CRM Server 在其工具下没有显示

    一.使用TFS 代码管理,发现Visual Studio 2012 菜单栏 工具下的Connect to Dynamics CRM Server 没有显示. 平常打开VS下的工具都会出现Connect ...

  7. 5.验证用户名是否已经被注册:AJAXC请求

    首先在 web.xml 文件中添加配置信息 <!-- 配置全局的字符集 --> <context-param> <param-name>encode</par ...

  8. Find minimum continuous subsequence tags

    Given targetList, a list of strings representing the desired tags, and availableTagList, a list of s ...

  9. 可以ping通ip地址,但是访问80,或者8080报错

    这个是服务器的防火墙的原因,一般linux防火墙默认是打开的,并且只开放22端口,用于远程连接. 这个时候需要关闭防火墙,或者开放端口.

  10. idea如何禁用SVN

    打开Intellij的setting(ctrl+alt+s),选择plugins,在右边搜索框输入“SVN”,搜索.选择“SVN disconnect”,安装此插件.  插件使用 点击菜单栏中的VCS ...