如何在PHP中实现完整的Observer模式


How to implement a full Observer pattern in PHP

观察者设计模式是松耦合对象的解决方案,因此它们可以一起工作。在PHP中,只需使用两个类就可以轻松地实现这一点。

基本上,您有一个主体,它能够通知并更新其状态更改的观察者列表。

我试图解决的问题是知道如何处理警告观察者他们正在观察的对象的不同状态

例如,假设我们有一个文件上传类,我们将日志记录类、websockets类和图像大小调整类附加到该类。每个正在观看的类都想了解上传过程中的不同事件。

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

  • 上载时出错(警报日志记录类)
  • 上传成功(提醒websockets类)
  • 上传成功,是图像文件(提醒图像调整类)

这是一个非常基本的例子,但如何处理不同观察者可能需要了解的多个事件?单独调用notifyObserver()是不够的,因为每个观察者都需要知道被通知的内容。

一个想法是,我可以通过调用来说明正在观察到的事件类型:

$this->notifyObservers('upload.error', this);

然而,这意味着我必须为观察者本身添加自定义切换,以了解如何处理不同的事件。

function observe($type, $object)
{
    if($type === 'upload.error') $this->dosomething();
    elseif($type === 'something.else') $this->otherthing();
    ...etc...
}

我发现这很丑陋,因为它开始将观察者与他们正在观察的班级联系起来。

再说一遍,如果我只是通知观察者,而没有传递任何关于刚刚发生的事件的信息,他们必须自己猜测发生了什么,这意味着更多的if()检查。

观察者实际上并没有耦合到他们正在观察的类。观察者的处理程序和观察到的对象之间的连接是使用文字字符串值(例如"upload.error")进行的,这意味着:

  1. 如果你想观察一个特定的对象,你必须事先知道它将发布的事件的名称;这就是你不喜欢的"耦合"
  2. 另一方面,如果您只对特定事件感兴趣,则可以在不了解该对象的情况下观察该事件的任何类型的对象

上面的第2项是你关心的福利,但第1项该怎么办?

如果你仔细想想,需要有一些方法来区分对同一观察者的回调,如果它们代表发生的不同事件。这些"标识符",无论采取何种形式,都需要打包到被观察对象中,或者作为观察者库代码的一部分。

在第一个实例中(在被观察对象内部),在开始观察该事件的目标之前,您可能需要一种方法让观察者查询"您是否发布过事件X?"。目标可以很好地回答这个问题。这留下了耦合的苦涩味道,但如果你想让任何物体观察任何其他物体,而你事先不知道你会观察到什么,我认为你做得再好不过了。

在第二种方法中,您将在库中定义许多众所周知的事件(在类中定义为const?)。据推测,之所以可以生成这样的事件列表,是因为库处理了一个具体的应用程序域,而该域为事件提供了明显的选择。然后,库内部的类(最终会被观察到)和库外部的类(插入框架的观察者)都会使用这些标识符来区分事件。许多基于回调的API(如Win32)使用的方法实际上与此相同。