编程语言-Java系列设计模式

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

2021-01-13  本文已影响0人  AbstractCulture

回调函数

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

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

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

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("食物已到达,请下楼取餐");
    }
}
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();
    }
}
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

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

重构回调函数

package com.xjm.design.eventlistener.callback;

/**
 * @author jaymin
 * 2021/1/10 21:41
 */
public interface Callback {

    void callback();

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

这里使用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 回调函数解读

事件监听器模式

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

事件监听器模式组成成员

eventListener

代码示例

定义事件发布的内容

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;

}

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

package com.tea.design.eventlistener.pattern;

/**
 * @author jaymin<br>
 * 事件监听器<br>
 * 2021/1/11 22:18
 */
public interface EventListener {
    /**
     * 处理事件
     * @param event 事件
     */
    void processEvent(Event event);
}

监听事件进行日志打印

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

监听事件进行日志打印

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

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

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

总结

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


缺点:

扩展阅读

上一篇 下一篇

猜你喜欢

热点阅读