为什么人们在他们的代码中使用消息/事件总线?
我认为你已经听说过消息/事件总线,这是系统中所有事件stream动的唯一地点。 计算机主板和LANnetworking中也有类似的架构。 这对于主板和networking来说是一个很好的方法,因为它可以减less线路数量,但是对软件开发有好处吗? 我们没有电子产品这样的限制。
消息总线/事件总线的最简单实现可以是:
class EventBus { void addListener(EventBusListener l}{...} void fireEvent(Event e) {...} }
使用bus.fireEvent(event)完成发布事件,接收消息由bus.addListener(listener)启用。 这种体系结构有时用于软件开发,例如MVP4G为GWT实现类似的消息总线。
活跃项目:
- Google Guava EventBus
- 本杰明Diedrichsen 大使
- Mathieu Carbou的Mycila PubSub
- mvp4g事件总线
- 简单的Java事件总线
hibernate/死亡项目:
- Sun / Oracle JavaBeans InfoBus
- https://eventbus.dev.java.net/ [Broken link]
这只是stream行的Observer(Listener)模式“全局” – 系统中的每个对象都可以监听每条消息,我认为这很糟糕,它打破了封装原则(每个对象都知道所有事情)和单一责任原则某些对象需要新types的消息,事件总线通常需要更改,例如在Listener类中添加新的Listener类或新方法。
由于这些原因,我认为,对于大多数软件来说,观察者模式比事件总线更好。 你对事件总线有什么看法,对典型的应用程序有什么意义?
编辑:我不是在谈论'大'企业解决scheme,如ESB – 他们可以是有用的(还有什么比ESB提供更多,不仅仅是一个事件总线)。 我在询问在“常规”Java代码中使用消息总线进行对象到对象连接的有用性 – 有些人这样做,请检查上面的链接。 事件总线可能是电话到电话通信或计算机到计算机通信的最佳解决scheme,因为networking中的每个电话(或计算机)通常可以相互通话,并且总线减less了电线的数量。 但对象很less互相交stream – 一个对象可以拥有多less个合作者 – 3,5个?
有些人喜欢它,因为它是门面模式或中介模式的体现 。 它集中了诸如logging,警报,监视,安全等交叉活动。
有些人不喜欢它,因为它通常是一个单身的失败点。 每个人都必须知道。
我正在考虑使用内存事件总线为我的常规Java代码,我的理由如下
系统中的每个对象都可以监听每条消息,我认为这很糟糕,它破坏了封装原则(每个对象都知道所有事情)
我不知道这是否真的如此,我的类需要注册与事件总线开始,类似于观察者模式,一旦一个类已经注册了事件总线,只有具有适当的签名和注释的方法被通知。
和单一职责原则(例如,当某个对象需要新types的消息时,经常需要更改事件总线,例如在Listener类中添加新的Listener类或新方法)。
我完全不同意
事件总线往往需要改变
事件总线从不改变
我同意
add a new Listener class or a new method in the Listener class
这是如何打破SRP?,我可以有一个BookEventListener订阅所有事件有关我的图书实体,是的,我可以添加方法,但这个类仍然是粘性…
为什么我打算使用它? 它可以帮助我模拟我的域名的“何时”。
通常我们会听到一些东西,例如发送邮件“何时”购买书籍
我们去写下来
book.purchase(); sendEmail()
然后我们被告知当购买一本书时添加审计日志,我们去上面的片段
book.purchase(); sendEmail(); **auditBook();**
OCP违反了
我更喜欢
book.purchase(); EventBus.raiseEvent(bookPurchasedEvent);
然后根据需要继续添加处理程序为修改而closures扩展closures
谢谢
我在JavaScript中大量使用它。 可以有这么多的各种小部件,每当发生其他事情时都需要做某种动作 – 没有真正的对象所有权的层次结构。 与其将每个对象的引用传递给每个对象,或者只是将每个对象都作为全局对象,当某个特定的控件内部发生重大事件时,我可以发布“/ thisWidget / somethingHappened” – 而不是使用各种特定代码到其他小部件的API。 我有一个包含所有“布线”或“plubming”的类,因为他们喜欢在Java Spring框架中调用它。 这个类包含了所有我的小部件的引用,并且包含了在每个事件触发后发生的所有代码。
它是集中的,易于访问和维护,如果有一件事情发生变化,或者我希望在特定事件上发生新的过程,我不必search每一个类/对象/小部件,以找出某些事物正在处理中。 我可以去我的“操作员”课 – 一个特定事件发生时处理所有“接线”的课程,并且看到对这个事件的每一个反应。 在这个系统中,每个小部件完全不受其他小部件的影响。 它只是发布发生了什么或它正在做什么。
我无法理解你在问题中真正想问什么。 你举了一个简单的事件公共汽车的例子,它实际上只是一个不同的名字Observable
,然后你说;
由于这些原因,我认为,对于大多数软件来说,观察者模式比事件总线更好。 你对事件总线有什么看法,对典型的应用程序有什么意义?
但是举个例子,他们是一样的。 这让我怀疑你是否曾经使用过类似企业服务总线的东西。 在基本级别上,ESB在逻辑上与观察者模式完全相同,但是商业产品增加了很多。 它就像一个类固醇事件巴士。 他们是复杂的软件产品和报价;
消息提取
通过收听各种端点来生成事件。 端点可以是一个监听器(如HTTP服务器),一个消息传递系统(如JMS),一个数据库或几乎任何你想要的东西。
消息路由
把你的事件发送到一个/多个端点。 路由可以非常聪明,总线可能根据消息types,消息内容或任何其他标准来路由消息。 路由可以是智能和dynamic的。
消息转换
将消息转换为另一种格式,这可以像从XML到JSON或从数据库表上的行到HTTP请求那样简单。 数据本身可以进行转换,例如交换date格式。
数据丰富
通过调用服务添加或修改消息中的数据。 例如,如果邮件中有邮编,总线可能会使用邮政编码查询服务来添加地址数据。
..很多,很多。 当你开始研究细节时,你真的可以开始明白为什么人们使用这些东西。
一个很好的比喻是电话交换机,每个手机都可以拨打其他手机。 受损的手机可以调谐到其他对话中。 程序控制stream程像电线(任何人都是复杂的)!这与在两个端点之间具有连接/物理介质的要求类似。 所以对于N个手机,我们倾向于获得N个stream量,而不是每个新手机都有NC2(组合逻辑)stream量。
复杂性的降低意味着易于理解的代码。 让我们从你突出强调的要点开始:1.全球知识2.侵入性的修改。
全球知识:认为消息事件是一个信封。 从事件处理程序/发件人的angular度来看,没有数据被暴露,它看到一个信封(除非派生类试图使用'instanceof'检查来做一些检查)。 在一个好的OOPdevise中,这绝不会发生。
侵入式修改:可以使用全局事件处理方法,而不是事件特定的侦听器方法。 因此,我们有一个全球性的事件types(数据被支持并下载)。 这很像Java中的PropertyBeanSupport模型。 对于单个事件types,我们需要有一个发送者和监听者types。 这意味着每次看到新东西时都不需要修改公交/听众。 丑陋的下铸可以使用适配器模式(请不要启动另一个级别的redirect报价!)。 程序员可以用任何语言编写程序集。 所以需要常识和聪明是不能取代的。 我打算说的是它可以是一个有效的工具。
实际的事件接收器可以很容易地使用监听器(合成/代理)。 在这样的Java代码库中,侦听器看起来像独立的内部类声明(在某些IDE中标记了未使用的警告)。 这是在沙滩上玩球的两名球员,球员直到他们看到球才反应。
“@duffymo”指出另一个有趣的方面:“单点失败”。 这在理论上会影响驻留在存储器(RAM)中的任何对象,而不是MessageHandlers的特定对象。
因为将应用程序模块分解为基于服务的体系结构可能是一个重要的步骤。
因此,如果您不打算将应用程序的模块分离成独立的服务,那么Observer模式的本地实现将使它成为一个更简单的解决scheme。
但是如果你想构build一个微服务架构,那么事件总线将允许获得这种架构风格的好处,所以你可以更新和部署你的应用程序的一部分而不影响其他部分,因为它们只是连接在一起通过事件总线。
所以这里的主要问题是应用程序组件解耦的期望水平。
关于它的一些参考:
作为一个实际的例子,我们的应用程序与x服务器每隔x分钟同步一次,如果收到任何新数据,我们需要更新GUI。 现在,因为SyncAdapter运行在后台线程上,所以你不能简单地指向一个textview并修改它的属性,你必须冒出一个事件。 而确保你捕捉事件的唯一方法是如果你有一个共享的(静态的,单例)对象传递这个事件给订阅者来处理。