zoukankan      html  css  js  c++  java
  • java设计模式观察者模式和事件监听器模式

    文章转载于:http://www.java2000.net/p9452

    复习设计模式,看到observer观察者模式,说法是该模式和iterator迭代器模式类似已经被整合进jdk,但是jdk提供了两种接口: 

    一、java.util.Observer —— 观察者接口 对应: 
    java.util.Observable ——受查者根类 

    二、java.util.EventListener —— 事件监听/处理接口 对应: 
    java.util.EventObject —— 事件(状态)对象根类 

    研究了一下发现这两种接口的目的、功能其实是一样的(仅在事件模型的结构上有些许差异),先看EventListener事件监听器模式: 

    1、首要定义事件源对象(事件源相当于单击按钮事件当中的按钮对象、属于被监听者): 

    1. public class DemoSource {   
    2.     private Vector repository = new Vector();//监听自己的监听器队列   
    3.     public DemoSource(){}   
    4.     public void addDemoListener(DemoListener dl) {   
    5.            repository.addElement(dl);   
    6.     }   
    7.     public void notifyDemoEvent() {//通知所有的监听器   
    8.            Enumeration enum = repository.elements();   
    9.            while(enum.hasMoreElements()) {   
    10.                    DemoListener dl = (DemoListener)enum.nextElement();   
    11.                  dl.handleEvent(new DemoEvent(this));   
    12.            }   
    13.     }   
    14. }  
    [Java] view plaincopy
     
    1. public class DemoSource {  
    2.     private Vector repository = new Vector();//监听自己的监听器队列  
    3.     public DemoSource(){}  
    4.     public void addDemoListener(DemoListener dl) {  
    5.            repository.addElement(dl);  
    6.     }  
    7.     public void notifyDemoEvent() {//通知所有的监听器  
    8.            Enumeration enum = repository.elements();  
    9.            while(enum.hasMoreElements()) {  
    10.                    DemoListener dl = (DemoListener)enum.nextElement();  
    11.                  dl.handleEvent(new DemoEvent(this));  
    12.            }  
    13.     }  
    14. }  



    2、其次定义事件(状态)对象(该事件对象包装了事件源对象、作为参数传递给监听器、很薄的一层包装类):

    1. public class DemoEvent extends java.util.EventObject {   
    2.     public DemoEvent(Object source) {   
    3.       super(source);//source—事件源对象—如在界面上发生的点击按钮事件中的按钮   
    4.        //所有 Event 在构造时都引用了对象 "source",在逻辑上认为该对象是最初发生有关 Event 的对象   
    5.     }   
    6.     public void say() {   
    7.            System.out.println("This is say method...");   
    8.     }   
    9. }  
    [Java] view plaincopy
     
    1. public class DemoEvent extends java.util.EventObject {  
    2.     public DemoEvent(Object source) {  
    3.       super(source);//source—事件源对象—如在界面上发生的点击按钮事件中的按钮  
    4.        //所有 Event 在构造时都引用了对象 "source",在逻辑上认为该对象是最初发生有关 Event 的对象  
    5.     }  
    6.     public void say() {  
    7.            System.out.println("This is say method...");  
    8.     }  
    9. }  



    3、最后定义我们的事件侦听器接口如下:

    1. public interface DemoListener extends java.util.EventListener {   
    2.     //EventListener是所有事件侦听器接口必须扩展的标记接口、因为它是无内容的标记接口、   
    3.     //所以事件处理方法由我们自己声明如下:   
    4.     public void handleEvent(DemoEvent dm);   
    5. }  
    [Java] view plaincopy
     
    1. public interface DemoListener extends java.util.EventListener {  
    2.     //EventListener是所有事件侦听器接口必须扩展的标记接口、因为它是无内容的标记接口、  
    3.     //所以事件处理方法由我们自己声明如下:  
    4.     public void handleEvent(DemoEvent dm);  
    5. }  



    4、测试代码

    1. //定义具体的事件监听器:   
    2. public class DemoListener1 implements DemoListener {   
    3.        public void handleEvent(DemoEvent de) {   
    4.               System.out.println("Inside listener1...");   
    5.               de.say();//回调   
    6.        }   
    7. }   
    8.   
    9. public class TestDemo {   
    10.     DemoSource ds;   
    11.   
    12.     public TestDemo(){   
    13.       try{   
    14.                  ds = new DemoSource();   
    15.   
    16.                  //将监听器在事件源对象中登记:   
    17.                  DemoListener1 l1 = new DemoListener1();   
    18.                  ds.addDemoListener(l1);   
    19.                  ds.addDemoListener(new DemoListener() {   
    20.                             public void handleEvent(DemoEvent event) {   
    21.                                       System.out.println("Method come from 匿名类...");   
    22.                             }   
    23.                  });   
    24.   
    25.   
    26.                  ds.notifyDemoEvent();//触发事件、通知监听器   
    27.   
    28.            }catch(Exception ex) {ex.printStackTrace();}   
    29.     }   
    30.   
    31.     public static void main(String args[]) {   
    32.            new TestDemo();   
    33.     }   
    34. }  
    [Java] view plaincopy
     
    1. //定义具体的事件监听器:  
    2. public class DemoListener1 implements DemoListener {  
    3.        public void handleEvent(DemoEvent de) {  
    4.               System.out.println("Inside listener1...");  
    5.               de.say();//回调  
    6.        }  
    7. }  
    8.   
    9. public class TestDemo {  
    10.     DemoSource ds;  
    11.   
    12.     public TestDemo(){  
    13.       try{  
    14.                  ds = new DemoSource();  
    15.   
    16.                  //将监听器在事件源对象中登记:  
    17.                  DemoListener1 l1 = new DemoListener1();  
    18.                  ds.addDemoListener(l1);  
    19.                  ds.addDemoListener(new DemoListener() {  
    20.                             public void handleEvent(DemoEvent event) {  
    21.                                       System.out.println("Method come from 匿名类...");  
    22.                             }  
    23.                  });  
    24.   
    25.   
    26.                  ds.notifyDemoEvent();//触发事件、通知监听器  
    27.   
    28.            }catch(Exception ex) {ex.printStackTrace();}  
    29.     }  
    30.   
    31.     public static void main(String args[]) {  
    32.            new TestDemo();  
    33.     }  
    34. }  


    再看Observer观察者模式: 
    Observer和EventListener的区别仅仅在于它提前声明了事件处理方法: 
    update(Observable o, Object arg) 
    Observer模式当中不存在对应EventObject的角色,Observable被观察者就兼具了source事件源和EventObject事件对象两种角色,模型更简洁。 
    Observable被观察者根类就持有了观察者队列,也定义了类似notifyDemoEvent()的notifyObservers()方法... 

    除了结构有差异外实在看不出Observer观察者模式和EventListener事件监听/处理模式的不一样!请教二者还有什么差异吗? 


    回复: 

    也不能这么说 
    我看了一下Observer、Observable的jdk源码,Observer接口没什么可说的仅仅是声明了一个update方法而已,相当于我在interface DemoListener extends java.util.EventListener接口中定义的:handleEvent方法。 
    为什么声明呢?最主要的是Observer模式比较EventListener的不同之处还在于将大部分工作收归Observable根类完成。 
    我又看了看Observable根类,虽然代码也很短小但是比较精悍,至少要我自己写考虑不了这么全面。好比java2集合,我们自己也能做些hashmap、arraylist、栈、队但是可靠性应该是比不上jdk提供的。 

    总结一下Observer模式和EventListener的主要不同之处: 

    一、模型结构不同:EventListener是传统的c/s界面事件模型,分事件源和事件(状态)角色,事件源要经过事件的包装、成为事件的属性之一再传递给事件监听/处理者,这个事件监听者就相当于观察者。我记得好像VB或C#也是这种模型...而Observer模式的模型就简洁多了,没有分事件源和事件,二者合二为一为一个角色:被观察者,从字面语义上也应该这样,另一个是观察者角色。 

    二、就是我上面说的Observer模式比较EventListener的不同之处还在于将大部分工作收归Observable根类实现了、包括定义监听者队列、通知方法都实现了,我们只要继承、调用和传值就行了。 

    现在想想可能是EventListener监听机制是从c/s时代就延续下来的,而Observer模式则是和iterator迭代器模式同样被整合进jdk的,所以现在这两种功用存在交叉的api会同时存在。 

    也贴出来Observer模式演示代码来对比

    1. //观察者   
    2. class Watcher implements java.util.Observer {   
    3.   public void update(java.util.Observable obj, Object arg) {   
    4.     System.out.println("Update() called, count is "    
    5.                                 + ((Integer) arg).intValue());   
    6. }   
    7. }   
    8.            
    9. //被观察者   
    10. class BeingWatched extends java.util.Observable {   
    11.     void counter(int period) {   
    12.         for(; period>=0; period-- ) {   
    13.                 setChanged();   
    14.                 notifyObservers(new Integer(period));   
    15.                 try {   
    16.                         Thread.sleep(100);   
    17.                 } catch( InterruptedException e) {   
    18.                   System.out.println("Sleep interrupeted" );   
    19.                 }   
    20.         }   
    21. }   
    22. };   
    23.   
    24. //演示   
    25. public class ObserverDemo {   
    26.     public static void main(String[] args) {   
    27.         BeingWatched beingWatched = new BeingWatched();//受查者   
    28.         Watcher watcher = new Watcher();//观察者   
    29.         beingWatched.addObserver(watcher);   
    30.         beingWatched.counter(10);   
    31.     }   
    32. }  
    [Java] view plaincopy
     
    1. //观察者  
    2. class Watcher implements java.util.Observer {  
    3.   public void update(java.util.Observable obj, Object arg) {  
    4.     System.out.println("Update() called, count is "   
    5.                                 + ((Integer) arg).intValue());  
    6. }  
    7. }  
    8.           
    9. //被观察者  
    10. class BeingWatched extends java.util.Observable {  
    11.     void counter(int period) {  
    12.         for(; period>=0; period-- ) {  
    13.                 setChanged();  
    14.                 notifyObservers(new Integer(period));  
    15.                 try {  
    16.                         Thread.sleep(100);  
    17.                 } catch( InterruptedException e) {  
    18.                   System.out.println("Sleep interrupeted" );  
    19.                 }  
    20.         }  
    21. }  
    22. };  
    23.   
    24. //演示  
    25. public class ObserverDemo {  
    26.     public static void main(String[] args) {  
    27.         BeingWatched beingWatched = new BeingWatched();//受查者  
    28.         Watcher watcher = new Watcher();//观察者  
    29.         beingWatched.addObserver(watcher);  
    30.         beingWatched.counter(10);  
    31.     }  
    32. }  



    回复: 
    查阅了一些相关的东东 
    原来这两种api可以说都是基于:订阅-发布模式的事件/消息通知模式,二者应该都算是“推”方式吧,就是被监控者将消息通知给所有监控者。 
    1、订阅:Observable.addObserver; 
    事件源.addDemoListener(这个方法是自己定义的)。 

    2、发布:Observable需要两步:setChanged()、notifyObservers(newValue); 
    事件源.notifyDemoEvent()(这个方法也是自己定义的)。 

    有人说Observer是设计模式中的皇后,很多系统级实现都是这种方式,我觉得是不是搞混了,因为我看java.util.Observer的api没什么下级接口或实现类。 
    反倒是相似的java.util.EventListener有大量下级接口和实现类,著名的包括: 
    java.beans.PropertyChangeListener 
    javax.servlet.http.HttpSessionListener... 
    以及java界面api里的很多... 
    这么看EventListener比Observer应用多得多,我猜想是否是因为EventListener的限制较少、没有规定事件处理方法名、比如HttpSessionListener就根据自己的应用领域定义事件处理方法: 
    sessionCreated(HttpSessionEvent se) 和 
    sessionDestroyed(HttpSessionEvent se) 

    如果用Observer就只能叫update了。

  • 相关阅读:
    随机算法之舍伍德算法
    KMP算法笔记
    分治法求解最大子段和问题
    递归与分治之间的关系
    微信公众号开发学习笔记(一)
    关于echo$PATH中的PTAH来源
    【Leetcode】807. Max Increase to Keep City Skyline
    【Leetcode】804. Unique Morse Code Words
    【Leetcode】709. To Lower Case
    【Leetcode】Jewels and Stones
  • 原文地址:https://www.cnblogs.com/banxian/p/3781132.html
Copyright © 2011-2022 走看看