java設計模式--觀察者模式和事件監聽器模式

文章轉載於:http://www.java2000.net/p9452java

複習設計模式,看到observer觀察者模式,說法是該模式和iterator迭代器模式相似已經被整合進jdk,可是jdk提供了兩種接口: 

1、java.util.Observer —— 觀察者接口 對應: 
java.util.Observable ——受查者根類 

2、java.util.EventListener —— 事件監聽/處理接口 對應: 
java.util.EventObject —— 事件(狀態)對象根類 

研究了一下發現這兩種接口的目的、功能實際上是同樣的(僅在事件模型的結構上有些許差別),先看EventListener事件監聽器模式: 

一、首要定義事件源對象(事件源至關於單擊按鈕事件當中的按鈕對象、屬於被監聽者): 設計模式

  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 plain copy
 
  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. }  



二、其次定義事件(狀態)對象(該事件對象包裝了事件源對象、做爲參數傳遞給監聽器、很薄的一層包裝類):api

  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 plain copy
 
  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. }  



三、最後定義咱們的事件偵聽器接口以下:session

  1. public interface DemoListener extends java.util.EventListener {   
  2.     //EventListener是全部事件偵聽器接口必須擴展的標記接口、由於它是無內容的標記接口、   
  3.     //因此事件處理方法由咱們本身聲明以下:   
  4.     public void handleEvent(DemoEvent dm);   
  5. }  
[Java]  view plain copy
 
  1. public interface DemoListener extends java.util.EventListener {  
  2.     //EventListener是全部事件偵聽器接口必須擴展的標記接口、由於它是無內容的標記接口、  
  3.     //因此事件處理方法由咱們本身聲明以下:  
  4.     public void handleEvent(DemoEvent dm);  
  5. }  



四、測試代碼ide

  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 plain copy
 
  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的主要不一樣之處: 

1、模型結構不一樣:EventListener是傳統的c/s界面事件模型,分事件源和事件(狀態)角色,事件源要通過事件的包裝、成爲事件的屬性之一再傳遞給事件監聽/處理者,這個事件監聽者就至關於觀察者。我記得好像VB或C#也是這種模型...而Observer模式的模型就簡潔多了,沒有分事件源和事件,兩者合二爲一爲一個角色:被觀察者,從字面語義上也應該這樣,另外一個是觀察者角色。 

2、就是我上面說的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 plain copy
 
  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能夠說都是基於:訂閱-發佈模式的事件/消息通知模式,兩者應該都算是「推」方式吧,就是被監控者將消息通知給全部監控者。 
一、訂閱:Observable.addObserver; 
事件源.addDemoListener(這個方法是本身定義的)。 

二、發佈: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了。this

相關文章
相關標籤/搜索