事件中心与观察者模式

楔子

event一种我们在代码中经常使用的对象。我们通过一定的方式创建出一个event,然后调用上下文将event发送出去。对应的listener就会收到消息并执行响应的逻辑。
我们都知道这种基于“事件”的开发中,用到设计模式就是观察者模式(也叫发布订阅模式),那么什么是观察者模式呢?

观察者模式

观察者模式是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个“观察”该对象的其他对象。

事件中心demo

在观察者模式中有三个要素:

  1. 主题,也就是我们的事件中心
  2. 观察者,众多listener
  3. 被观察的对象,各种event

好了,定义我们已经了解了,那么如何使用观察者模式实现一个事件中心呢?

被观察者

首先我们定一下被观察者,也就是我们的事件对象

/**
 * 事件
 * @author skyline
 */
public class BaseEvent {

    private final Object data;

    public BaseEvent(Object data) {
        this.data = data;
    }

    public Object getData() {
        return data;
    }
}

具体的事件

从事件基类中继承而来的一个具有业务场景的具体事件。

/**
 * 到家了事件
 * @author skyline
 */
public class GetHomeEvent extends BaseEvent {
    public GetHomeEvent(String userName) {
        super(userName);
    }
}

观察者

接下来我们定义一下观察者

/**
 * 事件监听者
 * @author skyline
 */
public interface IEventListener<T extends BaseEvent> {

    /**
     * 监听,当有事件到来时,这个方法会被调用
     * @param event 事件
     */
    void listener(T event);
}

具体事件的具体观察者

/**
 * 空气净化器对回家监听
 */
public class AirCleanerGetHomeListener implements IEventListener<GetHomeEvent> {
    private static final Logger logger = LoggerFactory.getLogger(AirCleanerGetHomeListener.class);

    @Override
    public void listener(GetHomeEvent event) {
        logger.info("[{}]回来了,空气净化器已打开", event.getData());
    }
}
/**
 * wifi对回家监听
 */
public class WifiGetHomeListener implements IEventListener<GetHomeEvent> {
    private static final Logger logger = LoggerFactory.getLogger(WifiGetHomeListener.class);

    @Override
    public void listener(GetHomeEvent event) {
        logger.info("WiFi已自动连接到[{}]的手机", event.getData());
    }
}

主题

主题,也就是我们的事件中心。事件中心有两大基本能力,注册和发布

/**
 * 事件中心
 * @author skyline
 */
public interface IEventCenter {

    /**
     * 发布事件
     * @param event
     */
    void publishEvent(BaseEvent event);

    /**
     * 注册事件
     * @param eventListener
     */
    void registerEvent(IEventListener<? extends BaseEvent> eventListener);
}

具体的主题—>事件中心

/**
 * 事件中心
 *
 * @author skyline
 */
public enum EventCenter implements IEventCenter {
    /**
     * 单例
     */
    INSTANCE;

    private final Map<Class, List<IEventListener>> listenerMap = new HashMap<>();

    @Override
    public void publishEvent(BaseEvent event) {
        //根据event的类型获取对应的listener
        List<IEventListener> eventListeners = listenerMap.get(event.getClass());
        if (eventListeners != null) {
            eventListeners.forEach(eventListener -> eventListener.listener(event));
        }
        //如果发出的event不是BaseEvent,那就给所有对BaseEvent感兴趣的listener都发送一下消息
        if (!event.getClass().equals(BaseEvent.class)) {
            List<IEventListener> listeners = listenerMap.get(BaseEvent.class);
            if (listeners != null) {
                listeners.forEach(eventListener -> eventListener.listener(event));
            }
        }
    }

    @Override
    public void registerEvent(IEventListener<? extends BaseEvent> eventListener) {
        //建立起Listener感兴趣的Event类型与Listener的映射关系
        Class genericInterface = (Class) ((ParameterizedType) eventListener.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0];
        List<IEventListener> eventListeners = listenerMap.computeIfAbsent(genericInterface, k -> new ArrayList<>());
        eventListeners.add(eventListener);
    }
}

验证事件中心

public class Main {
    private static final Logger logger = LoggerFactory.getLogger(Main.class);

    public static void main(String[] args) {
        IEventCenter eventCenter = EventCenter.INSTANCE;
        eventCenter.registerEvent(new AirCleanerGetHomeListener());
        eventCenter.registerEvent(new WifiGetHomeListener());
        //不指定具体的event类型,就是对所有事件都感兴趣
        eventCenter.registerEvent(new IEventListener<BaseEvent>() {
            @Override
            public void listener(BaseEvent event) {
                logger.info("eventType[{}] getMessage [{}]", event.getClass().getSimpleName(), event.getData());
            }
        });
        eventCenter.publishEvent(new GetHomeEvent("张三"));
        eventCenter.publishEvent(new BaseEvent("李四"));
    }
}

好了,我们看下结果:

22:47:49.464 [main] INFO com.example.designpatterns.observer.AirCleanerGetHomeListener - [张三]回来了,空气净化器已打开
22:47:49.464 [main] INFO com.example.designpatterns.observer.WifiGetHomeListener - WiFi已自动连接到[张三]的手机
22:47:49.464 [main] INFO com.example.designpatterns.observer.Main - eventType[GetHomeEvent] getMessage [张三]
22:47:49.464 [main] INFO com.example.designpatterns.observer.Main - eventType[BaseEvent] getMessage [李四]

完全没有问题

总结

  1. 观察者模式定义了对象之间的一对多关系,比如在com.example.designpatterns.observer.EventCenter#listenerMap中存放了事件与监听器的一对多关系。
  2. 主题(也可能就是观察者)用一个共同的接口来更新观察者。就好像EventCenter调用com.example.designpatterns.observer.IEventListener#listener来触发事件一样。
  3. 当存在多个观察者时,不可以依赖特定的通知顺序
  4. 面向接口开发,解耦利器。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值