如何在PHP中实现完整的观察者模式

5

观察者设计模式是解决对象之间松散耦合以便它们可以一起工作的方案。在PHP中,您可以仅使用两个类就可以轻松实现这一点。

基本上,您有一个主题,它能够通知和更新其状态变化列表中的观察者。

我要解决的问题是如何处理向观察者报告它们正在观察的对象的不同状态的问题。

例如,假设我们有一个文件上传类,我们附加了一个记录类、WebSockets类和一个图像调整大小类。这些正在观察的类都想知道上传过程中的不同事件。

这个文件上传类可能有三个地方需要通知正在监听的类发生了某些事情。

  • 上传错误(警报记录类)
  • 上传成功(警报WebSockets类)
  • 上传成功并且是图像文件(警报图像调整大小类)
这是一个非常基本的例子,但是如何处理不同观察者可能需要知道的多个事件呢?仅调用notifyObservers()是不够的,因为每个观察者都需要知道它正在被通知的内容。
一个想法是,我可以在调用时说明正在观察的事件类型:
$this->notifyObservers('upload.error', this);

然而,这意味着我必须为观察者自身添加自定义切换功能,以了解如何处理不同的事件。
function observe($type, $object)
{
    if($type === 'upload.error') $this->dosomething();
    elseif($type === 'something.else') $this->otherthing();
    ...etc...
}

我发现这样做很丑陋,因为它开始将观察者与他们观察的类联系起来。
但是,如果我只通知观察者而不传递有关刚刚发生的事件的任何信息,他们必须自己猜测正在发生什么,这意味着需要更多的if()检查。
1个回答

5
观察者实际上并没有与其观察的类耦合。观察者处理程序和被观察对象之间的连接是使用文字字符串值(例如 `upload.error`)进行的,这意味着:
1. 如果您想要观察特定对象,则必须事先知道它将发布的事件的名称;这就是您不喜欢的“耦合”。
2. 另一方面,如果您只对特定事件感兴趣,可以观察任何类型的对象以获取该事件,而无需了解该对象。
以上第二点是您关心的好处,但是如何解决第一点呢?
如果您仔细考虑一下,需要有某种方式来区分回调是否表示发生不同的事件。这些“标识符”无论采取何种形式,都需要打包到观察对象中或成为观察者库代码的一部分。
在第一种情况下(在观察对象内部),您可能需要一种方法让观察者查询“您是否会发布事件X?”然后再开始观察该事件的目标。目标可以很好地回答这个问题。这留下了耦合的苦涩味道,但是如果您希望任何对象观察任何其他对象,并且您事先不知道您将要观察什么,我认为您无法做得更好。
在第二种方法中,您将在库中定义一些众所周知的事件(例如作为类内部的 `const`?)。假定可以制作此类事件列表,因为该库处理具体的应用程序域,并且该域为事件提供了明显的选择。然后,既是库内部的类(最终将被观察),也是外部类(插入框架的观察者)都将使用这些标识符来区分事件。许多基于回调的API(例如Win32)使用与此几乎完全相同的方法。

我刚刚发现了Symfony 事件调度器库,我认为他们处理得就像你说的那样。 - Xeoncross

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接