1. 程式人生 > >Java設計模式補充:回撥模式、事件監聽器模式、觀察者模式(轉)

Java設計模式補充:回撥模式、事件監聽器模式、觀察者模式(轉)

一、回撥函式

為什麼首先會講回撥函式呢?因為這個是理解監聽器、觀察者模式的關鍵。

什麼是回撥函式

所謂的回撥,用於回撥的函式。 回撥函式只是一個功能片段,由使用者按照回撥函式呼叫約定來實現的一個函式。 有這麼一句通俗的定義:就是程式設計師A寫了一段程式(程式a),其中預留有回撥函式介面,並封裝好了該程式。程式設計師B要讓a呼叫自己的程式b中的一個方法,於是,他通過a中的介面回撥自己b中的方法。

舉個例子:

這裡有兩個實體:回撥抽象介面、回撥者(即程式a)

回撥介面(ICallBack )

public interface ICallBack {
    public void callBack();
}

回撥者(用於呼叫回撥函式的類)

複製程式碼
public class Caller {

    public void call(ICallBack callBack){
        System.out.println("start...");
        callBack.callBack();
        System.out.println("end...");
    }

}
複製程式碼

回撥測試:

複製程式碼
public static void main(String[] args) {
       Caller call = new Caller();
       call.call(new ICallBack(){

        @Override
        
public void callBack() { System.out.println("終於回撥成功了!"); } }); }
複製程式碼

控制檯輸出:

start...

終於回撥成功了!

end...

還有一種寫法

複製程式碼
ICallBack callBackB = new ICallBack(){
        @Override
        public void callBack() {
            System.out.println("終於回撥成功了!");
        }           
};
call.call(callBackB);
複製程式碼

或實現這個ICallBack介面類

class CallBackC implements ICallBack{
        @Override
        public void callBack() {
            System.out.println("終於回撥成功了!");  
        }
}

有沒有發現這個模型和執行一個執行緒,Thread很像。 沒錯,Thread就是回撥者,Runnable就是一個回撥介面。

new Thread(new Runnable(){
        @Override
        public void run() {
             System.out.println("回撥一個新執行緒!");  
}}).start();

Callable也是一個回撥介面,原來一直在用。 接下來我們開始講事件監聽器

二、事件監聽模式

什麼是事件監聽器

監聽器將監聽自己感興趣的事件一旦該事件被觸發或改變,立即得到通知,做出響應。例如:Android程式中的Button事件。

Java的事件監聽機制可概括為3點:

  1. Java的事件監聽機制涉及到事件源,事件監聽器,事件物件三個元件,監聽器一般是介面,用來約定呼叫方式。
  2. 當事件源物件上發生操作時,它將會呼叫事件監聽器的一個方法,並在呼叫該方法時傳遞事件物件過去。
  3. 事件監聽器實現類,通常是由開發人員編寫,開發人員通過事件物件拿到事件源,從而對事件源上的操作進行處理。

舉個例子

這裡我為了方便,直接使用JDK,EventListener 監聽器,感興趣的可以去研究下原始碼,非常簡單。

監聽器介面

public interface EventListener extends java.util.EventListener {
    //事件處理
    public void handleEvent(EventObject event);
}

事件物件

複製程式碼
public class EventObject extends java.util.EventObject{
    private static final long serialVersionUID = 1L;
    public EventObject(Object source){
        super(source);
    }
    public void doEvent(){
        System.out.println("通知一個事件源 source :"+ this.getSource());
    }

}
複製程式碼

事件源

事件源是事件物件的入口,包含監聽器的註冊、撤銷、通知

複製程式碼
public class EventSource {
   //監聽器列表,監聽器的註冊則加入此列表
    private Vector<EventListener> ListenerList = new Vector<EventListener>();
    //註冊監聽器
    public void addListener(EventListener eventListener){
        ListenerList.add(eventListener);
    }
    //撤銷註冊
    public void removeListener(EventListener eventListener){
        ListenerList.remove(eventListener);
    }
 //接受外部事件
    public void notifyListenerEvents(EventObject event){        
        for(EventListener eventListener:ListenerList){
                eventListener.handleEvent(event);
        }
    }

}
複製程式碼

測試執行

複製程式碼
public static void main(String[] args) {
        EventSource eventSource = new EventSource();

        eventSource.addListener(new EventListener(){
            @Override
            public void handleEvent(EventObject event) {
                event.doEvent();
                if(event.getSource().equals("closeWindows")){
                    System.out.println("doClose");
                } 
            }

        });


        /*
         * 傳入openWindows事件,通知listener,事件監聽器,
         對open事件感興趣的listener將會執行
         **/
        eventSource.notifyListenerEvents(new EventObject("openWindows"));

}
複製程式碼

控制檯顯示:

通知一個事件源 source :openWindows

通知一個事件源 source :openWindows

doOpen something...

到這裡你應該非常清楚的瞭解,什麼是事件監聽器模式了吧。 那麼哪裡是回撥介面,哪裡是回撥者,對!EventListener是一個回撥介面類,handleEvent是一個回撥函式介面,通過回撥模型,EventSource 事件源便可回撥具體監聽器動作。

有了瞭解後,這裡還可以做一些變動。 對特定的事件提供特定的關注方法和事件觸發

複製程式碼
public class EventSource {
     ...
  public void onCloseWindows(EventListener eventListener){
        System.out.println("關注關閉視窗事件");
        ListenerList.add(eventListener);
    }

    public void doCloseWindows(){
        this.notifyListenerEvents(new EventObject("closeWindows"));
    }
    ...
}
public static void main(String[] args) {
     EventSource windows = new EventSource();
        /**
         * 另一種實現方式
         */
        //關注關閉事件,實現回撥介面
        windows.onCloseWindows(new EventListener(){

            @Override
            public void handleEvent(EventObject event) {
                event.doEvent();
                if(event.getSource().equals("closeWindows")){
                    System.out.println("通過onCloseWindows來關注關閉視窗事件:並執行成功。 closeWindows");
                }

            }

        });

       //視窗關閉動作
        windows.doCloseWindows();

}
複製程式碼

這種就類似於,我們的視窗程式,Button監聽器了。我們還可以為單擊、雙擊事件定製監聽器。

三、觀察者模式

什麼是觀察者模式

觀察者模式其實原理和監聽器是一樣的,使用的關鍵在搞清楚什麼是觀察者、什麼是被觀察者。

  • 觀察者(Observer)相當於事件監器。有個微博模型比較好理解,A使用者關注B使用者,則A是B的觀察者,B是一個被觀察者,一旦B發表任何言論,A便可以獲得。
  • 被觀察者(Observable)相當於事件源和事件,執行事件源通知邏輯時,將會回撥observer的回撥方法update。

舉個例子

為了方便,同樣我直接使用JDK自帶的Observer。

一個觀察者

複製程式碼
public class WatcherDemo implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        if(arg.toString().equals("openWindows")){
            System.out.println("已經開啟視窗");
        }
    }
}
複製程式碼

被觀察者

Observable是JDK自帶的被觀察者,具體可以自行看原始碼和之前的監聽器事件源類似。

主要方法有:

  • addObserver()新增觀察者,與監聽器模式類似。
  • notifyObservers()通知所有觀察者。

類Watched.java的實現描述:被觀察者,相當於事件監聽的事件源和事件物件。又理解為訂閱的物件 主要職責:註冊/撤銷觀察者(監聽器),接收主題物件(事件物件)傳遞給觀察者(監聽器),具體由感興趣的觀察者(監聽器)執行

複製程式碼
/**
 * 
 * 類Watched.java的實現描述:被觀察者,相當於事件監聽的事件源和事件物件。又理解為訂閱的物件
 * 主要職責:註冊/撤銷觀察者(監聽器),接收主題物件(事件物件)傳遞給觀察者(監聽器),具體由感興趣的觀察者(監聽器)執行
 * @author xuan.lx 2016年11月22日 下午3:52:11
 */
public class Watched extends Observable {

    public void notifyObservers(Object arg) {

        /**
         * 為避免併發衝突,設定了changed標誌位changed =true,則當前執行緒可以通知所有觀察者,內部同步塊會完了會設定為false;
       通知過程中,正在新註冊的和撤銷的無法通知到。
         */
        super.setChanged();
        /**
         * 事件觸發,通知所有感興趣的觀察者
         */
        super.notifyObservers(arg);

    }

}
複製程式碼

測試執行

複製程式碼
public static void main(String[] args) {
        Watched watched = new Watched();
        WatcherDemo watcherDemo = new WatcherDemo();
        watched.addObserver(watcherDemo);
        watched.addObserver(new Observer(){
            @Override
            public void update(Observable o, Object arg) {
                if(arg.toString().equals("closeWindows")){
                    System.out.println("已經關閉視窗");
                }
            }
        });
        //觸發開啟視窗事件,通知觀察者
        watched.notifyObservers("openWindows");
        //觸發關閉視窗事件,通知觀察者
        watched.notifyObservers("closeWindows");

}
複製程式碼

控制檯輸出:

已經開啟視窗

已經關閉視窗

總結

從整個實現和呼叫過程來看,觀察者和監聽器模式基本一樣。

有興趣的你可以基於這個模型,實現一個簡單微博加關注和取消的功能。 說到底,就是事件驅動模型,將呼叫者和被呼叫者通過一個連結串列、回撥函式來解耦掉,相互獨立。

整個設計模式的初衷也就是要做到低耦合,低依賴。

再延伸下,訊息中介軟體是什麼一個模型?將生產者+服務中心(事件源)和消費者(監聽器)通過訊息佇列解耦掉. 訊息這相當於具體的事件物件,只是儲存在一個佇列裡(有消峰填谷的作用),服務中心回撥消費者介面通過拉或取的模型響應。 想必基於這個模型,實現一個簡單的訊息中介軟體也是可以的。

還比如Guava ListenableFuture,採用監聽器模式就解決了future.get()一直阻塞等待返回結果的問題。

有興趣的同學,可以再思考下觀察者和責任鏈之間的關係, 我是這樣看的。

同樣會存在一個連結串列,被觀察者會通知所有觀察者,觀察者自行處理,觀察者之間互不影響。 而責任鏈,講究的是擊鼓傳花,也就是每一個節點只需記錄繼任節點,由當前節點決定是否往下傳。 常用於工作流,過濾器Web Filter。

相關推薦

Java設計模式補充模式事件監聽器模式觀察模式

一、回撥函式為什麼首先會講回撥函式呢?因為這個是理解監聽器、觀察者模式的關鍵。什麼是回撥函式所謂的回撥,用於回撥的函式。 回撥函式只是一個功能片段,由使用者按照回撥函式呼叫約定來實現的一個函式。 有這麼一句通俗的定義:就是程式設計師A寫了一段程式(程式a),其中預留有回撥函式

Java設計模式補充調模式事件監聽器模式觀察模式

應該 hand 關閉 lan china 關註 update 使用 event 一、回調函數 為什麽首先會講回調函數呢?因為這個是理解監聽器、觀察者模式的關鍵。 什麽是回調函數 所謂的回調,用於回調的函數。 回調函數只是一個功能片段,由用戶按照回調函數調用約定來實現的

javaweb監聽器接口-觀察模式

監聽器javaweb監聽器接口有8個分別是ServletRequestListener,HttpSessionListener,ServletContextListener, ServletRequestAttributeListener,HttpSessionAttributeListener,Servle

事件驅動模型和觀察模式

你有一件事情,做這件事情的過程包含了許多職責單一的子過程。這樣的情況及其常見。當這些子過程有如下特點時,我們應該考慮設計一種合適的框架,讓框架來完成一些業務無關的事情,從而使得各個子過程的開發可以專注於自己的業務。  這些子過程有一定的執行次序; 這些子過程之間需要較靈活

【C#】Event事件的應用之觀察模式

using System; namespace Event { // 在遊戲設計中,通常會出現這樣的場景,有一個正在巡邏的敵軍隊伍,當玩家攻擊了其中之一的敵人時 // 那個隊伍的所有敵人都會注意到玩家,並且開始攻擊玩家 // 以下便是個觀察者模式的簡略程式碼

Java中泛型T和Class<T>以及Class<?>的理解

tcl ota 特定 類型 基本 ext pla enum extend 註意:class是java的關鍵字, 在聲明Java類時使用; Class類的實例表示Java應用運行時的類(class ans enum)或接口(interface and annotatio

DeepMind詳解新WaveNet比原來快千倍,語音更自然 | 附論文 DeepMind詳解新WaveNet比原來快千倍,語音更自然 | 附論文

mark一下,感謝作者分享! https://blog.csdn.net/yh0vlde8vg8ep9vge/article/details/78621165 原 DeepMind詳解新WaveNet:比原來快千倍,語音更自然 |

highcharts入門之Pie如何讓Pie餅狀圖的圖例內顯示百分比

有很多人都在詢問如何在highcharts的pie 餅狀圖內顯示百分比,通過不斷琢磨最後得出了一個結論,只需要簡單配置即可實現這樣一個需求。 完整核心程式碼如下所示: $(function () { var chart; //

Java設計模式-函式和觀察模式

Android的框架中有非常多的地方使用了回撥的模式,例如Activity的生命週期,按鈕的點選事件等。 下面是回撥的基本模型: public class A { private CallBack callback; //註冊一個事件 public void reg

Java中的設計模式觀察模式

name int 還要 The else 意圖 http exceptio 所有 介紹 觀察者模式是行為設計模式之一。當您對對象的狀態感興趣並希望在有任何更改時收到通知時,觀察者設計模式非常有用。在觀察者模式中,監視另一個對象狀態的對象稱為Observer,正在被監視的對象

Java設計模式11觀察模式

一、什麼是觀察者模式 在閻巨集博士的《JAVA與模式》一書中開頭是這樣描述觀察者(Observer)模式的:   觀察者模式是物件的行為模式,又叫釋出-訂閱(Publish/Subscribe)模式、模型-檢視(Model/View)模式、源-監聽器(Source/Listener)模式

Java程式效能優化 讀書筆記設計模式觀察模式

一、觀察者模式 觀察者模式定義了物件間的一種一對多依賴關係,使得每當一個物件改變狀態,則所有依賴於它的物件都會得到通知並被自動更新。它將觀察者和被觀察者的物件分離開。提高了應用程式的可維護性和重用性。觀察者模式又稱為釋出/訂閱(Publish/Subscribe)模式。 觀

Java設計模式觀察模式Observer Pattern

觀察者模式:類似於報紙和雜誌的訂閱 出版者+訂閱者=觀察者模式 1.報紙的業務就是出版報紙。 2.向某家報社訂閱報紙,只要他們有新報紙出版,就會給你送來。只要你是他們的訂閱使用者,你就會一直收到新報紙。 3.當你不想再看報紙時,取消訂閱,他們就不會再

Java設計模式觀察模式以及Servlet中的Listener

觀察者模式(Observer Pattern)也稱釋出訂閱模式,它是一種在實際開發中經常用到的一種模式。 觀察者模式定義:定義物件一種一對多的依賴關係,使得每當一個物件改變狀態時,則所依賴它的物件會得到通知並被自動更新。 觀察者類圖如下: 圖1 觀察者模式的類圖  觀

Java中的設計模式 - 觀察模式【又叫釋出/訂閱模式

文章目錄 Java中的設計模式 - 觀察者模式【又叫:釋出/訂閱模式】 1、觀察者模式是為了解決什麼問題 2、核心邏輯 3、優點 4、缺點 5、應用場景

Java設計模式觀察模式(Observer)

觀察者模式定義了物件間的一種一對多依賴關係,使得每當一個物件改變狀態,則所有依賴於它的物件都會得到通知並被自動更新。 它將觀察者和被觀察者的物件分離開。提高了應用程式的可維護性和重用性。 實現觀察者模式有很多形式,一種是“註冊---通知---撤銷註冊”的形式。 觀察者Observer:所有潛在的觀察

Java函式和觀察模式的區別

    前一段時間研究了一下設計模式,突然想到觀察者模式和回撥函式之間的聯絡,網上也沒有什麼人說清楚,便自己又仔細想了想,便有了如下觀點,歡迎各位大神前來拍磚!     首先,先闡述一下網上說的,網上先說這是完全不同的兩種東西,介面回撥是觀察者模式的實現,後者是一種設計模式

Java描述設計模式(11)觀察模式

本文原始碼:GitHub·點這裡 || GitEE·點這裡 一、觀察者模式 1、概念描述 觀察者模式是物件的行為模式,又叫釋出

重學 Java 設計模式實戰觀察模式「模擬類似小客車指標搖號過程,監聽訊息通知使用者中籤場景」

![](https://img-blog.csdnimg.cn/20200630231649444.png) 作者:小傅哥 部落格:[https://bugstack.cn](https://bugstack.cn) - `原創系列專題文章` >沉澱、分享、成長,讓自己和他人都能有所收穫!

JAVA設計模式之單例模式

單例對象 日誌 locking anti 常見 基本上 title 加載 懶漢式 本文繼續介紹23種設計模式系列之單例模式。 概念:  java中單例模式是一種常見的設計模式,單例模式的寫法有好幾種,這裏主要介紹三種:懶漢式單例、餓漢式單例、登記式單例。  單例模式有以下特