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

时间:2011-06-16 15:21:12

标签: php observer-pattern

Observer Design Pattern是松散耦合对象的解决方案,因此它们可以一起工作。在PHP中,您可以使用two classes轻松实现此功能。

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

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

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

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

  • 上传错误(警报记录类)
  • 上传成功(alert websockets class)
  • 上传成功并且是图像文件(警报图像调整大小类)

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

有一种想法是,我可以通过电话说明正在观察什么类型的事件:

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

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

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

我觉得非常难看,因为它开始将观察者联系回他们正在观察的班级。

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

1 个答案:

答案 0 :(得分:5)

观察者实际上并没有与他们观察的班级联系在一起。观察者的处理程序和观察对象之间的连接是使用文字字符串值(例如`upload.error')进行的,这意味着:

  1. 如果你想观察一个特定的对象,你必须事先知道它将要发布的事件的名称;这是你不喜欢的“耦合”。
  2. 另一方面,如果您只对特定事件感兴趣,则可以观察该事件的任何类型的对象,而无需了解该对象。
  3. 上面的第2项是您关心的一项好处,但如何处理第1项?

    如果您考虑一下,如果它们代表不同的事件发生,则需要通过某种方式区分同一观察者的回调。这些“标识符”,无论采用何种形式,都需要打包到观察对象中或作为观察者库代码的一部分。

    在第一个实例中(观察对象内部)你可能需要一种方法让观察者查询“你有没有发布过事件X?”在开始观察该事件的目标之前。目标可以很好地回答这个问题。这留下了偶然的苦涩味道,但是如果你想让任何对象观察到任何其他对象,并且你不知道你将会事先观察到什么,我认为你不能做得更好。< / p>

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