zoukankan      html  css  js  c++  java
  • Java设计模式——观察者模式(事件监听)

    最近在看Tomcat和Spring的源码,在启动的时候注册了各种Listener,事件触发的时候就执行,这里就用到了设计模式中的观察者模式。

    引-GUI中的事件监听

    想想以前在学Java的GUI编程的时候,就用到了事件的注册监听,然后写了一个小程序试验一下:
    点击按钮触发相应的事件

    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);
    
    }
    
    

    我们可以在这里,再定义事件监听类,这些类具体实现了监听功能和事件处理功能。也可以用下面主程序中的匿名内部类来实现。原理一样。

    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();
        }
    }
    
    

    运行:

    开
    关
    

    仔细分析下程序,和我们之前YY的监听器其实大致一样,
    个人觉得最难理解的就是事件对象SwitchEvent了。
    问题
    1.为什么要继承EventObject?不继承行不行
    2.事件和事件源有什么联系,为什么还需要事件对象
    答:
    1.继承自EventObject只是为了规范,不实现当然可以。在handleEvent的时候,我们可以通过事件对象拿到我们需要的东西,这里面就有最基本的source,也就是这里的switch对象了,
    2.事件和事件源关系并不大,事件对象里面包含source罢了,通过构造函数注入。

    [参考]

    设计模式学习----观察者模式(事件监听实现)
    java事件处理机制(自定义事件)

  • 相关阅读:
    cf1108E2 线段树类似扫描线
    poj1185 状态压缩经典题
    cf1110F 离线+树上操作+线段树区间更新
    tarjan求lca :并查集+dfs
    cf1110E 思维
    cf1110d 线性dp
    cf842D 01字典树|线段树 模板见hdu4825
    cf842C 树形dp+gcd函数
    cf581F 依赖背包+临时数组 好题
    hdu5758 思维,树形dp
  • 原文地址:https://www.cnblogs.com/aheizi/p/5547237.html
Copyright © 2011-2022 走看看