Java設計模式——觀察者模式(事件監聽)

最近在看Tomcat和Spring的源碼,在啓動的時候註冊了各類Listener,事件觸發的時候就執行,這裏就用到了設計模式中的觀察者模式。html

引-GUI中的事件監聽

想一想之前在學Java的GUI編程的時候,就用到了事件的註冊監聽,而後寫了一個小程序試驗一下:
點擊按鈕觸發相應的事件java

public class ButtonTest extends JFrame {
    ButtonTest() {
        JPanel panel = new JPanel();
        JButton button1 = new JButton("按鈕一");
        JButton button2 = new JButton("按鈕二");

        panel.add(button1);
        panel.add(button2);
        this.getContentPane().add(panel);
        this.setVisible(true);

        button1.addActionListener(
                new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        System.out.println("你按了按鈕一");
                    }
                });
        button2.addActionListener(
                new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        System.out.println("你按了按鈕二");
                    }
                });
    }

    public static void main(String args[]) {
        new ButtonTest();
    }
}

嗯,寫起來確實很簡單,這是封裝好的,咱們只須要註冊事件,並實現對應的事件響應就好了。
那麼這種神奇的模式是怎麼實現的呢?
如下爲個人分析過程。o(╯□╰)o
首先,咱們來回歸本質,看看到底這種模式方便在哪兒。若是不這麼作的話,咱們須要再每次點擊按鈕的代碼裏面把響應的內容加上,若是有一千個事件響應,咱們須要把這一千個響應都寫到點擊按鈕這個方法裏面,Oh!!MyGod!太麻煩了!
若是忘掉設計模式,咱們想一想這種事情應該怎麼作呢?
咱們須要把這一千個響應管理起來,而後在事件觸發的時候,把這些響應統一調用,不就好了?問題來了...
1.如何管理起來?
2.每一個響應都不同,每次寫響應的時候都須要去點擊事件那裏加一段,改動之前的代碼,此乃編程之大忌,耦合度過高
想一想回答,
1.把每個響應都經過一個響應鏈來管理,觸發事件時,遍歷這個響應鏈,作出響應。
2.能夠定義一個接口,在響應的地方傳入該接口,調用接口的方法。這樣,每次須要響應的時候,實現該接口,傳入具體響應的對象,這樣咱們就只用關心如何響應了,不用關心如何去調用響應的辦法。
暈了暈了暈了……
來看看Java中的事件處理機制是如何實現的吧!編程

Java中的事件處理機制

來自維基百科的結構圖:

圖看看就行。
場景:按下開關,燈作出的響應。
1.定義事件對象小程序

/**
 * 事件對象。繼承EventObject
 * Created by HuangYQ on 2016/5/31.
 */
public class SwitchEvent extends EventObject {

    private String switchState;     //表示開關的狀態

    public SwitchEvent(Switch source, String switchState) {
        super(source);
        this.switchState = switchState;
    }

    public void setSwitchState(String switchState) {
        this.switchState = switchState;
    }

    public String getSwitchState() {
        return switchState;
    }
}

2.定義事件監聽接口設計模式

/**
 * 事件監聽接口
 * Created by HuangYQ on 2016/5/31.
 */
public interface SwitchListener extends EventListener {

    public void handleEvent(SwitchEvent switchEvent);

}

咱們能夠在這裏,再定義事件監聽類,這些類具體實現了監聽功能和事件處理功能。也能夠用下面主程序中的匿名內部類來實現。原理同樣。ide

3.定義事件源對象(具體的事件源,好比說,你點擊一個button,那麼button就是event source,要想使button對某些事件進行響應,你就須要註冊特定的listener。這裏指開關)函數

/**
 * 電源開關
 * 事件源對象,相似於Swing中的button
 * Created by HuangYQ on 2016/5/31.
 */
public class Switch {

    private Vector switchListenerList = new Vector();

    public void addListener(Object listener) {
        switchListenerList.add(listener);
    }

    protected void open() {
        SwitchEvent switchEvent = new SwitchEvent(this, "開");
        notifyListeners(switchEvent);
    }

    protected void close() {
        SwitchEvent switchEvent = new SwitchEvent(this, "關");
        notifyListeners(switchEvent);
    }

    private void notifyListeners(SwitchEvent switchEvent) {
        Iterator iterator = switchListenerList.iterator();
        while (iterator.hasNext()) {
            SwitchListener switchListener = (SwitchListener) iterator.next();
            switchListener.handleEvent(switchEvent);
        }
    }

}

4.主程序學習

public class SwitchMain {

    public static void main(String[] args) {
        Switch switchTest = new Switch();
        switchTest.addListener(new SwitchListener() {
            @Override
            public void handleEvent(SwitchEvent switchEvent) {
                //Do what ever you want !
                System.out.println(switchEvent.getSwitchState());
            }
        });

        //觸發
        switchTest.open();
        switchTest.close();
    }
}

運行:ui

開
關

仔細分析下程序,和咱們以前YY的監聽器其實大體同樣,
我的以爲最難理解的就是事件對象SwitchEvent了。
問題
1.爲何要繼承EventObject?不繼承行不行
2.事件和事件源有什麼聯繫,爲何還須要事件對象
答:
1.繼承自EventObject只是爲了規範,不實現固然能夠。在handleEvent的時候,咱們能夠經過事件對象拿到咱們須要的東西,這裏面就有最基本的source,也就是這裏的switch對象了,
2.事件和事件源關係並不大,事件對象裏面包含source罷了,經過構造函數注入。this

[參考]

設計模式學習----觀察者模式(事件監聽實現)
java事件處理機制(自定義事件)

相關文章
相關標籤/搜索