1. 程式人生 > >java設計模式--觀察者模式和事件監聽器模式

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

觀察者模式

觀察者模式又稱為訂閱—釋出模式,在此模式中,一個目標物件管理所有相依於它的觀察者物件,並且在它本身的狀態改變時主動發出通知。這通常透過呼叫各觀察者所提供的方法來實現。此種模式通常被用來事件處理系統。

基於事件驅動機制的系統或語言,比如node.js、nio等,不難發現其最終的基礎模式就是觀察者模式,只是不同的應用場景,也會有各自不同的側重。

觀察者

class Watcher implements java.util.Observer {   
  public void update(java.util.Observable obj, Object arg) {   
    System.out.println("Update() called, count is "    
                                + ((Integer) arg).intValue());   
}   
}  

被觀察者
class BeingWatched extends java.util.Observable {   
    void counter(int period) {   
        for(; period>=0; period-- ) {   
                setChanged();   
                notifyObservers(new Integer(period));   
                try {   
                        Thread.sleep(100);   
                } catch( InterruptedException e) {   
                  System.out.println("Sleep interrupeted" );   
                }   
        }   
}   
};   

測試
public class ObserverDemo {   
    public static void main(String[] args) {   
        BeingWatched beingWatched = new BeingWatched();//受查者   
        Watcher watcher = new Watcher();//觀察者   
        beingWatched.addObserver(watcher);   
        beingWatched.counter(10);   
    }   
}  

監聽器模式
事件源經過事件的封裝傳給監聽器,當事件源觸發事件後,監聽器接收到事件物件可以回撥事件的方法

1、首要定義事件源物件(事件源相當於單擊按鈕事件當中的按鈕物件、屬於被監聽者):

public class DemoSource {   
    private Vector repository = new Vector();//監聽自己的監聽器佇列   
    public DemoSource(){}   
    public void addDemoListener(DemoListener dl) {   
           repository.addElement(dl);   
    }   
    public void notifyDemoEvent() {//通知所有的監聽器   
           Enumeration enum = repository.elements();   
           while(enum.hasMoreElements()) {   
                   DemoListener dl = (DemoListener)enum.nextElement();   
                 dl.handleEvent(new DemoEvent(this));   
           }   
    }   
}  

2、其次定義事件(狀態)物件(該事件物件包裝了事件源物件、作為引數傳遞給監聽器、很薄的一層包裝類):
public class DemoEvent extends java.util.EventObject {   
    public DemoEvent(Object source) {   
      super(source);//source—事件源物件—如在介面上發生的點選按鈕事件中的按鈕   
       //所有 Event 在構造時都引用了物件 "source",在邏輯上認為該物件是最初發生有關 Event 的物件   
    }   
    public void say() {   
           System.out.println("This is say method...");   
    }   
}  
3、最後定義我們的事件偵聽器介面如下
public interface DemoListener extends java.util.EventListener {   
    //EventListener是所有事件偵聽器介面必須擴充套件的標記介面、因為它是無內容的標記介面、   
    //所以事件處理方法由我們自己宣告如下:   
    public void handleEvent(DemoEvent dm);   
}
監聽器實現類
public class DemoListener1 implements DemoListener {   
       public void handleEvent(DemoEvent de) {   
              System.out.println("Inside listener1...");   
              de.say();//回撥   
       }   
} 
4、測試程式碼
public class TestDemo {   
   DemoSource ds;   
   public TestDemo(){   
      try{   
         ds = new DemoSource();   
         //將監聽器在事件源物件中登記:   
         DemoListener1 listener1 = new DemoListener1();   
         ds.addDemoListener(listener1);   
         ds.addDemoListener(new DemoListener() {   
            public void handleEvent(DemoEvent event) {   
            System.out.println("Method come from 匿名類...");   
          }   
        });   
       ds.notifyDemoEvent();//觸發事件、通知監聽器   
     }catch(Exception ex){
       ex.printStackTrace();
       }   
    }   
  
    public static void main(String args[]) {   
           new TestDemo();   
    }   
}  

總結
監聽器模式是觀察者模式的另一種形態,同樣基於事件驅動模型。監聽器模式更加靈活,可以對不同事件作出相應。但也是付出了系統的複雜性作為代價的,因為我們要為每一個事件源定製一個監聽器以及事件,這會增加系統的負擔

釋出訂閱
觀察者模式實現釋出訂閱,可以新增一個排程中心,降低publisher和subscriber的耦合,具體實現中,有兩個版本。
1) 拉模式:目標角色在發生變化後,僅僅告訴觀察者角色“我變化了”;觀察者角色如果想要知道具體的變化細節,則就要自己從目標角色的介面中得到。拉模式是想要就主動表白獲取。

2) 推模式:通知你發生變化的同時,通過一個引數將變化的細節傳遞到觀察者角色中去。推模式是管你要不要,先給你啦。
這兩種模式的使用,取決於系統設計時的需要。如果目標角色比較複雜,並且觀察者角色進行更新時必須得到一些具體變化的資訊,則“推模式”比較合適。如果目標角色比較簡單,則“拉模式”就很合適啦。

事件和訊息的區別
事件本身即是具有特定業務含義的一種固定結構物件,而訊息是資料傳輸過程中的載體。概念上寬泛來講,事件可以稱作是一種訊息,而訊息不能代替事件。事件反映的是特定的業務狀態,比如訂單建立、服務呼叫失敗、應用宕機等。
一個事件物件描述的是誰在什麼時間做了什麼事情,看到這個物件,我們就能知道是發生了什麼特定的事情。但是事件物件本身不承載資料傳遞的職能。
訊息中介軟體實現的是訊息的儲存,解決的是解耦上下游業務系統。事件處理系統是更多的側重對事件的分析處理,並驅動業務的進一步扭轉。