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) {
            /**
             * source—事件源對象—如在界面上發生的點擊按鈕事件中的按鈕 所有 Event 在構造時都引用了對象 "source",在邏輯上認為該對象是最初發生有關 Event 的對象
             */
            super(source);
        }

        public void say() {
            System.out.println("This is say method...");
        }

    }

  

3、最后定義我們的事件偵聽器接口如下

 public interface DemoListener extends java.util.EventListener {

        /**
         * EventListener是所有事件偵聽器接口必須擴展的標記接口、因為它是無內容的標記接口、
         *
         * 所以事件處理方法由我們自己聲明如下:
         * @param dm
         */
        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();

        }

    }

  

總結

1、Observer的實現相對簡單,event-listener需要實現三個角色,observer-observable需要實現兩個角色。
2、Observable的api已經把對觀察者的注冊,刪除等定義好了,而且是線程安全的。而event-listener需要使用者自己實現。
3、兩者都需要自己定義並實現觸發事件的通知。但Observable需要注意要在通知Observer之前調用jdk提供的setChanged()。
4、event-listener是傳統的c/s界面事件模型,分事件源和事件(狀態)角色,事件源要經過事件的包裝、成為事件的屬性之一再傳遞給事件監聽/處理者,這個事件監聽者就相當於觀察者。Observer更簡潔一些。兩者在思想上是統一的,很多框架仍然使用了event-listener模式,比如spring框架的ApplicationEvent,ApplicationListener。
5、監聽器模式是觀察者模式的另一種形態,同樣基於事件驅動模型。監聽器模式更加靈活,可以對不同事件作出相應。但也是付出了系統的復雜性作為代價的,因為我們要為每一個事件源定制一個監聽器以及事件,這會增加系統的負擔。

 

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

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

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM