免责声明:这个答案与 Symfony EventDispatcher 无关,但与您的问题有关。如果您只想得到答案,您可以跳过(某种程度上)学术讨论并跳到最后。
讨论
FACT:应用程序大小的增加意味着复杂性的相应增加。
随着应用程序范围的扩大,您会发现自己添加了越来越多的类来实现必需的功能。突然间,想起来并不那么容易了Foo
当对象需要执行某些特定操作时Bar
对象被创建。此外,当您的对象开始为彼此提供补充功能时,在不以非常紧密耦合的对象结束的情况下维持必要的关系变得越来越困难。
我们需要一种方法让对象能够进行通信,而无需对显式引用进行硬编码,而当某些内容发生变化时我们会忘记更改这些引用。那么,我们如何管理快速增长的对象图的节点之间的这种相互关联的功能呢?
如果你想让它持久,你就必须说话
让我们稍微绕一下,考虑一个浪漫的比喻......
任何关系要想长久,都需要持续的沟通。当然,你和你的伴侣可以在周六晚上聚在一起进行阴暗的勾搭,而在本周剩下的时间里不互相交谈。然而,这种类型的沟通通常会导致脆弱的关系,双方都不了解对方实际上需要什么才能在这种关系中正常运作。
继续类比,随着时间的推移,你的性格会慢慢发生变化(而且它会发生变化),缺乏沟通会阻止你的伴侣理解如何最好地与你互动。最终,所有违背的承诺和未接的电话都达到了顶峰,关系就不再有效了。它坏了。
您的应用程序以同样的方式工作。代码应该足够成熟,可以说:“嘿宝贝,我可能会改变,但如果我改变了,我保证我会永远让你知道我发生了什么。”不幸的是,随着复杂性的增加,传统的直线应用程序设计使得在类之间没有紧密耦合的情况下很难维持这种通信。
进入活动管理
这就是事件管理的意义所在。目标是为我们的对象提供一种相互通信的方式,而不会硬编码与需要通信的对象的关系。与大多数编程问题一样,没有单一的、具体的、“正确”的方法来做到这一点。您的问题特别提到了实现此目的的两种可用方法,因此我将解决这些方法。如果您想了解其他一些选项,@ircmaxell 最近发布了一篇关于使 PHP 应用程序“可插拔”的不错的调查博客文章 http://blog.ircmaxell.com/2012/03/handling-plugins-in-php.html.
Observer
在实践中,您会发现很少有适用于观察者模式的实际 PHP 应用程序。这是因为,如果您希望代码非常动态,那么很快您就可以将观察者附加到各处的主题对象。
当这种情况发生时,你就得到了你开始试图实现的松散耦合,但你却产生了不同类型的问题:手动附加所有观察者和主题。例如,如果应用程序中的每个类都是某个类的主题,那么您就为自己创建了大量工作。Logger
观察者对象。还,IMHO此方法有时会将可能更准确地描述为主题的实际依赖项的内容从主题构造函数的方法签名中移出,从而使您的 API 变得模糊。
如果我们使用集中式调度程序在事件发生时通知感兴趣的对象,我们的应用程序将会更加灵活,尽管观察者模式对于一次性或简单的情况可能是理想的选择。
Mediator
A more robust way to manage events is by inserting a centralized layer to handle dispatching events to the appropriate listeners. This is what the Mediatorwiki http://en.wikipedia.org/wiki/Mediator_pattern pattern (and the Symfony event dispatcher) does.
中介者的要点在于,它是系统中每个事件的集中中转站,因此需要在整个应用程序范围(或中介部分)中访问它。仔细注意一下,这个does not意味着您应该将其视为全局变量并使用全局关键字随意访问中介器或将其包装在某种邪恶的单例对象或静态属性/方法中。这种滥用将导致@liquorvicar在第一个答案中提出的问题。然而,我强烈不同意该答案的评估:
“在您的应用程序中拥有一个无处不在且几乎可以完成所有操作的 eventDispatcher 会使您的代码更难测试/理解/维护等(它可以接近上帝对象)”
仅当您滥用 Mediator 时才会出现这种情况;它应该发送事件通知而不是其他任何内容。我会警告您不要像您在选项中建议的那样扩展它(2)因为这个原因你的问题。如果使用得当,中介对象是非常可测试的。没有什么比模拟构造函数中指定的依赖对象的行为更简单的了。这就是单元测试的意义所在。
Answer
因此,如果您在应用程序中需要非线性事件管理,我强烈建议选择(1)从你的问题来看。只要你不滥用它,这是完全可以接受的。掩饰 Symfony 实现,它似乎支持任何可作为侦听器调用的 PHP。就我个人而言,我更喜欢一个允许延迟实例化基于类的侦听器的系统,以获得更高效和面向对象的范例,但实现细节取决于您。
责任链模式与中介者密切相关,是实现类似结果的另一种有效方法。如果您有兴趣,我建议您使用之前发布的 @ircmaxell 博客文章的链接。