美文网首页编程语言-Java系列设计模式
[设计模式]事件监听器模式

[设计模式]事件监听器模式

作者: AbstractCulture | 来源:发表于2021-01-13 23:19 被阅读0次

    回调函数

    先从生活中的例子来理解这种过程:
    我点了一份外卖,外卖到了外卖小哥会自动拨打我的电话通知我去拿外卖。
    这个过程就是回调。

    OK,这是一个simple的过程,那么用代码来实现如何实现。

    实现一个简单的回调函数模型

    • UserOrder
    package com.xjm.design.eventlistener.callback;
    
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    /**
     * @author jaymin<br>
     * 客户,负责点餐和留下联系方式<br>
     * 2021/1/10 21:16
     */
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class UserOrder {
        /**
         * 食物名称
         */
        private String foodName;
    
        public UserOrder(DeliveryPerson deliveryPerson){
            deliveryPerson.supply(UserOrder.builder().foodName("冰红茶").build());
        }
    
        /**
         * 联系方式,配送员送到之后通过这个方法通知客户
         */
        public void callback(){
            System.out.println("食物已到达,请下楼取餐");
        }
    }
    
    • DeliveryPerson
    package com.xjm.design.eventlistener.callback;
    /**
     * @author jaymin<br>
     * 配送员,负责按照客户的要求进行配送,配送完后通知客户进行用餐。<br>
     * 2021/1/10 21:17
     */
    public class DeliveryPerson {
    
        public void supply(UserOrder userOrder){
            System.out.println("当前用户下单的食品清单:"+userOrder.getFoodName());
            System.out.println("到达商家拿到食物");
            System.out.println("抵达客户留下的地址,通知客户进行取餐");
            userOrder.callback();
        }
    }
    
    • CallbackDemo
    package com.xjm.design.eventlistener.callback;
    
    /**
     * @author jaymin
     * 2021/1/10 21:34
     */
    public class CallbackDemo {
        public static void main(String[] args) {
            UserOrder userOrder = new UserOrder(new DeliveryPerson());
        }
    }
    
    • Result
    Result

    这样有什么坏处?硬编码了,不利于扩展.下面我们通过接口来实现多态.

    重构回调函数

    • Callback
    package com.xjm.design.eventlistener.callback;
    
    /**
     * @author jaymin
     * 2021/1/10 21:41
     */
    public interface Callback {
    
        void callback();
    
    }
    
    • DeliveryPerson
    package com.xjm.design.eventlistener.callback;
    
    /**
     * @author jaymin<br>
     * 配送员,负责按照客户的要求进行配送,配送完后通知客户进行用餐。<br>
     * 2021/1/10 21:17
     */
    
    public class DeliveryPerson {
        private String foodName;
        private Callback callback;
    
    
        public DeliveryPerson(Callback callback, String foodName) {
            this.callback = callback;
            this.foodName = foodName;
        }
    
        public void execute() {
            System.out.println("当前用户下单的食品清单:" + foodName);
            System.out.println("到达商家拿到食物");
            System.out.println("抵达客户留下的地址,通知客户进行取餐");
            callback.callback();
        }
    }
    
    • CallbackDemo

    这里使用lambda来代替内部类,写法上更加简洁.

    package com.xjm.design.eventlistener.callback;
    
    /**
     * @author jaymin
     * 2021/1/10 21:34
     */
    public class CallbackDemo {
        public static void main(String[] args) {
            new DeliveryPerson(()-> System.out.println("食物已到达,请下楼取餐"),"冰红茶").execute();
        }
    }
    

    调用过程

    callback

    JDK中的回调函数-Runnable接口

    Thread类中内置了一个private Runnable target;,在start的时候会回调Runnable接口的run方法.

            new Thread(()-> System.out.println("callback")).start();
    

    扩展阅读

    java 回调函数解读

    事件监听器模式

    由一组监听器订阅特定事件的发布,一旦该事件进行了发布,所有的监听器都会做出响应,其中的响应则是上文所述的回调函数.

    事件监听器模式组成成员

    • 事件源: Event Source.被监听的对象,一旦事件源发生某个动作时,则调用其内置的事件监听器的方法,将事件对象进行广播.
    • 事件监听器: Event Listener. 监听事件源,可以对事件进行判断,进而响应.
    • 事件对象: Event Object.事件,通常为事件源广播的内容。
    eventListener

    代码示例

    • Event

    定义事件发布的内容

    package com.tea.design.eventlistener.pattern;
    
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    /**
     * @author jaymin<br>
     * 事件对象.<br>
     * 2021/1/11 22:10
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    public class Event {
    
        private String message;
    
    }
    
    • EventListener

    定义事件监听器接口,声明处理事件的方法

    package com.tea.design.eventlistener.pattern;
    
    /**
     * @author jaymin<br>
     * 事件监听器<br>
     * 2021/1/11 22:18
     */
    public interface EventListener {
        /**
         * 处理事件
         * @param event 事件
         */
        void processEvent(Event event);
    }
    
    • OfflineNewsEventListener

    监听事件进行日志打印

    package com.tea.design.eventlistener.pattern;
    
    import lombok.extern.slf4j.Slf4j;
    
    /**
     * @author jaymin
     * 2021/1/11 22:28
     */
    @Slf4j
    public class OfflineNewsEventListener implements EventListener{
        @Override
        public void processEvent(Event event) {
            log.info("日报头条:今天大事件:{}",event.getMessage());
        }
    }
    
    • OnlineNewsEventListener

    监听事件进行日志打印

    package com.tea.design.eventlistener.pattern;
    
    import lombok.extern.slf4j.Slf4j;
    
    /**
     * @author jaymin<br>
     * 如果发生大新闻,网络传媒要处理报道.<br>
     * 2021/1/11 22:27
     */
    @Slf4j
    public class OnlineNewsEventListener implements EventListener {
        @Override
        public void processEvent(Event event) {
            log.info("微博爆料:今天的爆炸新闻:{}", event.getMessage());
        }
    }
    
    • EventSource

    事件源,提供注册监听器方法与发布事件方法

    package com.tea.design.eventlistener.pattern;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author jaymin
     * 2021/1/11 22:30
     */
    public class EventSource {
        /**
         * 将所有的监听者进行存储
         */
        private List<EventListener> listenerList = new ArrayList<>();
    
        /**
         * 注册监听者
         * @param eventListener
         */
        public void addListener(EventListener eventListener){
            listenerList.add(eventListener);
        }
    
        /**
         * 发布事件
         * @param event
         */
        public void publishEvent(Event event){
            listenerList.forEach(eventListener -> eventListener.processEvent(event));
        }
    }
    
    • EventListenerDemo
    package com.tea.design.eventlistener.pattern;
    
    /**
     * @author jaymin
     * 2021/1/11 22:33
     */
    public class EventListenerDemo {
        public static void main(String[] args) {
            EventSource eventSource = new EventSource();
            OnlineNewsEventListener onlineNewsEventListener = new OnlineNewsEventListener();
            OfflineNewsEventListener offlineNewsEventListener = new OfflineNewsEventListener();
            eventSource.addListener(onlineNewsEventListener);
            eventSource.addListener(offlineNewsEventListener);
            eventSource.publishEvent(Event.builder().message("特朗普被推特永久封禁!").build());
        }
    }
    
    • Result
    result

    总结

    事件监听器模式与观察者模式大同小异,实现的思想是让被监听者/被观察者持有所有的监听器类,当需要是事件发布的时候,对这些监听器进行消息广播。
    监听器实现至统一的接口,事件源会将事件对象作为参数进行传输,然后每个监听器处理自己对应的业务.
    这体现了面向接口编程的设计原则,让代码耦合度更加松散。


    缺点:

    • 多个监听器操作同一事件对象,监听器与监听器无法感知对方对该对象进行了什么操作。
    • 同步调用,如果部分监听器执行时间长,会增加耗时。可以采用异步处理的方式规避.

    扩展阅读

    • JDK中的观察者模式
    • 消息队列的broker消费模式
    • Spring容器的事件监听器应用

    相关文章

      网友评论

        本文标题:[设计模式]事件监听器模式

        本文链接:https://www.haomeiwen.com/subject/xzcmaktx.html