当前位置: 首页 > 知识库问答 >
问题:

MVP::事件总线模式而不是监听器

李成礼
2023-03-14

这个问题更倾向于范式。为什么我们不在 MVP 环境中使用事件总线而不是侦听器?通常,“P”部件具有视图和模型引用的依赖关系注入。当然,这有一个优点,即通过表示器显示视图和模型之间的显式契约,这更具可读性。

但是,让演示者侦听来自视图的事件并且事件携带视图负载(例如:json表示形式)不是一种更干净的方法吗?演示者回过头来对视图说话也是如此。视图将侦听来自演示者的事件。主要优点是,我们不必为视图和表示器之间的每个合约编写接口。如果你看一下代码,你会看到演示者正在公开视图细节,如文本字段,我相信这正在增加视图和演示者之间的耦合。比如说,如果我要替换前端JavaFx而不是Vaadin,我也将不得不改变演示者。

这个课程是一个真实项目的例子。这里我们有不同类型的事件,即我没有为不同的情况创建事件类。例如:LoginViewEvent,DashBoardEvent等,我认为这是一个维护难题。

public class UrayEvent {

    public static enum EventType {

        SESSION_SELECTED(1),
        DOCUMENT_SELECTED(2),
        DOCUMENT_EDIT_COMPLETE(3),
        DOCUMENT_EDIT_CANCELED(4),
        SHOW_SESSION_TABLES(5),
        SHOW_SESSION_DOCUMENTS(6),
        SHOW_SESSION_COLLABORATORS(7),
        USER_REQUESTED_REFRESH(8),
        AUTO_REFRESH(9),
        TABLE_SELECTED(10),
        DETACHED(11),
        SCHEDULER_NAVIGATION(12),
        JIRA_USER_SELECTED(13),
        DOCUMENT_SAVE_SUCCESS(14),
        DOCUMENT_SAVE_FAILURE(14);

        private final int value;

        private EventType(int value) {

            this.value = value;
        }

        public int getValue() {

            return value;
        }
    }

    public static class Event {

        private final EventType type;
        private final Object payload;

        public Event(EventType type, Object eventPayload) {

            this.type = type;
            this.payload = eventPayload;
        }

        public EventType getEventType() {

            return type;
        }

        public Object getEventPayload() {

            return payload;
        }
    }

}

很简单,视图将事件发送到DOCUMENT_EDIT_COMPLETE。表示器层处理此事件。我发现通过这种方式,一种将视图与演示者分离的更好方法。

    @Subscribe
    public void handle(UrayEvent.Event event) {

        switch (event.getEventType()) {
            case DOCUMENT_EDIT_COMPLETE:
                  // event payload contains document model data
                  // like document id etc
                 saveDocument(event.getEventPayload);    
                break;
            default:
                break;
        }
    }

优势

  • 更少的锅炉板代码,对于n-视图,我们不需要n-接口
  • 新事件意味着将事件元素添加到枚举并更新处理此事件的相应订阅方法

不足之处

  • 如果我们忘记从事件总线取消注册,则内存泄漏(面对它很多时间)

问题

1) 这种方法意味着,随着应用程序的增长,会有更大的集合枚举元素。这是一种反模式吗?

2) 正如我们看到的,它广泛使用事件总线,使用总线系统而不是接口侦听器模式有什么缺点吗?

在这方面需要你的宝贵建议。主要问题是,如果我在整个项目中盲目地应用这种模式,我不应该后悔这样做,那么这种方法可能会有什么陷阱。

共有1个答案

缑嘉玉
2023-03-14

1)这种方法意味着,随着应用程序的增长,会有更大的set枚举元素。这种方法是反模式吗?

如果有许多事件,你需要许多事件标识符。它们可以是简单的< code>int或< code>enum或< code>Interface

您演示的机制很简单,适用于小型应用程序。它已在多个框架中多次得到验证。以Microsoft的Win32 APIMFC为例。

在一些项目中,我看到了使用 Annotations 实现的事件拦截器,它为处理事件提供了一种优雅的方式。上一次是在一个使用阿帕奇三柱门框架的项目中。

2) 正如我们看到的,它广泛使用事件总线,使用总线系统而不是接口侦听器模式有什么缺点吗?

在不同的包中,它基本上是相同的。在Java世界中,使用侦听器接口是事实上的标准。以摇摆Android为例

事件总线方法用于Facebook基于Javascript的React框架。有趣的是注意到模型视图呈现器和Flux设计模式的相似性。特别是单向数据流在这两种架构中都得到了强调。

你提到了用< code>Vaadin替换< code>JavaFx作为UI框架的用例。在我看来,改变UI框架以便能够重用它的某些部分是很少发生的。我不会因为框架可能会改变而预先付出增加抽象层和复杂性的代价。相反,你应该从亲吻和YAGNI原则开始。如果您以后想要更改UI框架,那么您只需从头开始再次实现UI层。

 类似资料:
  • 本文向大家介绍什么是事件监听?相关面试题,主要包含被问及什么是事件监听?时的应答技巧和注意事项,需要的朋友参考一下 参考回答: addEventListener()方法,用于向指定元素添加事件句柄,它可以更简单的控制事件,语法为 element.addEventListener(event, function, useCapture); 第一个参数是事件的类型(如 "click" 或 "mouse

  • Blade 中提供一个方法帮助开发者可以自定义的监听应用程序运行中的一些生命周期。比如 Session 的创建与销毁,应用启动结束后等。 支持的事件类型有如下: public enum EventType { SERVER_STARTING, // 服务准备启动 SERVER_STARTED, // 服务启动成功 SERVER_STOPPING, //

  • Nutz.Ioc 容器有三种事件: 对象被创建(create事件) 对象被从容器中取出(fetch事件) 对象被销毁(depose事件) 在这三种时刻,你如果想做一些特殊的操作,比如,当一个数据源被销毁时,你希望能够关闭所有的连接, 声明一下,你想监听什么事件,以及怎么监听。 注: 如果你的对象是 "singleton: false",那么容器创建了对象后就会立即忘记它的存在。因为鬼才知道 你打算

  • 全局事件 事件监听 注解监听 以imi/src/Listener/Init.php为例 <?php namespace Imi\Listener; use Imi\Event\EventParam; use Imi\Event\IEventListener; use Imi\Bean\Annotation\Listener; /** * @Listener(eventName="IMI.IN

  • Chrome DevTools命令行API提供了多种方式来观察和检查事件监听器。JavaScript在交互式页面中起着中心作用,并且浏览器为您提供了一些有用的工具来调试事件和事件处理程序。 TL;DR 使用monitorEvents()监听某一类型的事件。 使用unmonitorEvents()停止监听。 使用getEventListeners()获取DOM元素的监听器。 使用Event List

  • sTree触发容器上的各种事件。您可以查看所有事件的列表以了解要听的内容。 要获取有关事件的更多信息,请检查其data参数。 在大多数情况下,涉及节点的情况下,您将传递整个节点对象。如果在某处获取ID字符串并想要检查该节点,则只需使用 .get_node()。内部节点对象与用于加载的JSON格式非常相似,但是具有一些额外的属性,这可能很有用:children是节点的直接子节点的children_d