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了。

  • 相关阅读:
    sqlserver中判断表或临时表是否存在
    Delphi 简单方法搜索定位TreeView项
    hdu 2010 水仙花数
    hdu 1061 Rightmost Digit
    hdu 2041 超级楼梯
    hdu 2012 素数判定
    hdu 1425 sort
    hdu 1071 The area
    hdu 1005 Number Sequence
    hdu 1021 Fibonacci Again
  • 原文地址:https://www.cnblogs.com/banxian/p/3781132.html
Copyright © 2011-2022 走看看