事件(或消息)驱动的系统(具有两种风格 )具有一些好处。 我已经讨论了为什么我认为它们被过度使用了 。 但这不是我现在要写的。
我将(非常简短地)写有关“依赖关系”和“耦合”的文章。 似乎当我们消除编译时依赖性时,我们消除了组件之间的耦合。 例如:
class CustomerActions {
void purchaseItem(int itemId) {
//...
purchaseService.makePurchase(item, userId);
}
}
与
class CustomerActions {
void purchaseItem(int itemId) {
//...
queue.sendMessage(new PurchaseItemMessage(item, userId));
}
}
看来您的CustomerActions
类不再依赖于PurchaseService
。 不管谁将处理PurchaseItem
消息。 当然会有一些PurchaseService
处理消息,但是前一类在编译时并没有绑定。 这看起来像是“松散耦合”的一个很好的例子。 但事实并非如此。
首先,这两个类可能首先是松散耦合的。 一个与另一个交互的事实并不意味着它们是耦合的-只要PurchaseService
保持其makePurchase
方法的合同,它们就可以*地独立更改。
其次,消除了编译时依赖性并不意味着我们消除了逻辑依赖性。 事件已发送,我们需要一些东西来接收和处理它。 在许多情况下,这是同一VM /部署中的单个目标类。 *的文章定义了一种根据数据衡量耦合的方法 。 上面两种方法有什么不同? 否-在第一种情况下,我们将不得不更改方法定义,在第二种情况下,我们将更改事件类定义。 而且,我们仍然有一个处理类,在更改合同后,我们可能还必须更改其逻辑。 在某种程度上,即使在编译时未明确实现,前一类仍然在逻辑上依赖于后者。
关键是,逻辑耦合仍然存在。 仅将其移至事件中并不能带来“应许”的好处。 实际上,它使代码更难以阅读和跟踪。 在前一种情况下,您只是简单地向IDE请求一个呼叫层次结构,而跟踪谁产生和谁使用给定消息则可能比较困难。 事件方法有一些优点-事件可以推送到队列中,但可以直接调用(例如,通过代理,例如spring仅使用一个@Async批注)。
当然,这是一个简化的用例。 更复杂的应用程序将从事件驱动的方法中受益,但是在我看来,这些用例很少涵盖整个应用程序体系结构。 它们通常更适合于特定问题,例如NIO库。 我将继续保留这一常识性口头禅–不要做任何事情,除非您知道它给您带来的好处是什么。
翻译自: https://www.javacodegeeks.com/2015/08/events-dont-eliminate-dependencies.html