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

发布于 2024-11-16 01:10:19 字数 1090 浏览 1 评论 0原文

观察者设计模式是松散耦合对象的解决方案,以便它们可以一起工作。在 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() 检查。

An Observer Design Pattern is the solution to loosely coupling objects so they can work together. In PHP you can easily implement this using just two classes.

Basically, you have a subject which is able to notify and update a list of observers of its state changes.

The problem I'm trying to solve is to know how to handler alerting the observers about different states of the object they are watching.

For example, lets say we have a file upload class to which we attach a logging class, websockets class, and a image resize class. Each of these classes that are watching want to know about different events in the upload process.

This file upload class might have three places where it needs to notify the classes listening that something has happend.

  • Error With Upload (alert logging class)
  • Upload success (alert websockets class)
  • Upload success and is image file (alert image resize class)

This is a very basic example, but how do you handle multiple events that different observers may need to know about? Calling notifyObservers() alone wouldn't be enough since each observer needs to know what it is being notified about.

One thought is that I could state with the call what type of event is being observed:

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

However, that would mean I would have to add custom switching to the observers themselves to know how to handle different events.

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

I find that very ugly as it starts to couple the observers back to the class they are observing.

Then again, if I just notify Observers without passing any information about what event just happens - they have to guess themselves what is going on which means more if() checks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

苏佲洛 2024-11-23 01:10:19

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

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

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

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

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

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

The observers aren't actually coupled to the class they are observing. The connection between the observer's handler and the observed object is made using literal string values (e.g. `upload.error'), which means that:

  1. If you want to observe a specific object, you have to know from beforehand the names of the events it will publishing; this is the "coupling" that you don't like.
  2. On the other hand, if you are interested in a specific event only, you can observe any type of object for that event without having any knowledge about that object.

Item 2 above is a benefit that you care about, but what to do about item 1?

If you think about it, there needs to be some way to differentiate between callbacks to the same observer if they represent different events taking place. These "identifiers", no matter what form they take, need to be packaged either into the observed object or be a part of the observer library code.

In the first instance (inside observed object) you would probably need a way for observers to query "do you ever publish event X?" before starting to observe a target for that event. The target can answer this question just fine. This leaves a bitter taste of coupling, but if you want any object to observe any other, and you have no idea what you will be observing beforehand, I don't think you can do any better.

In the second approach, you would have a number of well-known events defined (as const inside a class?) in your library. Presumably such a list of events can be made because the library tackles a concrete application domain, and that domain offers obvious choices for the events. Then, classes both internal to your library (which would end up being observed) and external to it (the observers which plug into the framework) would use these identifiers to differentiate between events. Many callback-based APIs (such as Win32) use an approach practically identical to this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文