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

Xeo*_*oss 5 php observer-pattern

一个观察者设计模式是解决松散耦合的对象,使他们能够协同工作.在PHP中,您只需使用两个类即可轻松实现此功能.

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

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

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

此文件上载类可能有三个位置需要通知监听发生了某些事情的类.

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

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

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

$this->notifyObservers('upload.error', this);
Run Code Online (Sandbox Code Playgroud)

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

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

我发现它非常难看,因为它开始将观察者耦合回他们正在观察的类.

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

Jon*_*Jon 5

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

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

上面的第2项是您关心的一项好处,但如何处理第1项?

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

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

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