不知何故,您必须将容器变成主题。
这里的主要问题是找到一种有效的方法来注意到变化。大多数情况下,当您遇到此问题时,是因为您要观察的事物没有提供有效的通知机制(可能是因为在编写事物时并未发明观察者设计模式)。
[编辑] 既然你要求一种有效的方法,一般的答案是“这取决于”。设计模式没有“一刀切”的解决方案。它们是解决问题的一般规则。您需要如何在特定情况下实施规则是您在这种情况下解决的问题。
通常,如果您的观察者需要识别小的更改(即属性更改或添加元素),通知消息应该包含足够的信息,以便他们可以有效地执行此操作。所以如果你有一个大列表和一个插入,发送列表和新元素的索引加上“插入的项目”。
至于属性变化,有两种解决方案。一种是为列表中的每个元素添加一个观察者。这可能很慢并且需要大量 RAM,但这意味着您可以将多种类型添加到同一个列表中。
或者,您可以有一个“修改列表服务中的项目”。这意味着禁止直接更改项目,您必须始终使用该服务。然后,该服务可以作为主题工作,并发送带有项目、旧值和更改值以及可能带有列表中的索引的通知。
[EDIT2] 一般规则是尽可能多地收集有关更改的信息并将其传递给观察者。但这真的取决于你的具体问题。假设观察者坐在远程机器上。在这种情况下,没有有效的方法将整个列表发送给它。您只能发送“项目 X 已插入”并希望这就足够了。如果容器无法注意到变化(例如,网站上的新网页),则容器必须一次又一次地遍历整个站点以找到变化,然后以有效的方式告诉观察者。
同样,细节确实取决于具体情况。谷歌运行数千个网络蜘蛛,每小时访问数百万个网页。长期以来,这是“有效的”(如“唯一的方式”)。不久前,实施了“站点地图”协议,允许管理员将他们的网站变成可以告诉 Google 观察者有关更改的主题。
所以除非你能给出一个更具体的例子你需要做什么,否则我不能给你更具体的答案。对于设计模式,有一点你需要坐下来,解决一个真正的问题并打开你的大脑。
[EDIT3] 这里有几个使用观察者模式的例子:
许多 UI 框架使用这种模式将事件传播给感兴趣的各方。在 Qt 中,您有一个中心点,所有主题都可以在其中注册他们的信号(他们将发送的通知),并且观察者可以附加到主题上。这意味着有一个地方可以管理所有连接。优点是您不需要将此数据结构添加到每个对象。此外,来自外部的对象(非 Qt 对象)可以发送和接收消息。由于一切都在一个地方,因此可以轻松优化此数据结构。缺点是这种结构可能会变得非常大,因此当涉及更多方(即使是完全不相关的方)时,发送消息将花费更多时间。
Google 使用站点地图协议将网站转换为主题,因为这比一次又一次地遍历整个站点更有效,即使您只请求 URL 的最后修改时间(HTTP HEAD 而不是 HTTP GET)。
Windows 和 Linux 中的文件系统提供通知以告知应用程序有关新文件或已删除文件的信息。这里的主要问题是当应用程序未运行时文件更改时会发生什么。假设您有一个应用程序维护目录中文件的校验和。显然,您想知道应用程序关闭时的更改,但这意味着通知服务必须跟踪它发送的最后一次更改。所以在这里,应用程序必须在启动时读取整个树以查看它可能遗漏的任何内容,并且它需要使用观察者模式来在运行时发生变化。
邮件客户端是观察者。它将告诉邮件服务器它看到的最后一封电子邮件的 ID,并且服务器将告诉它任何新邮件。
当您在复杂模型中有大量属性更改时,通常是集中所有更改(使它们通过一个地方运行)并将观察者附加到那里(而不是将 N 个观察者附加到 M 个单独对象)的唯一方法。在这个实现中,观察者可以说“我对任何地方的任何变化感兴趣”或“任何主题中字段 X 的变化”或“主题 Y 的任何变化”(最后一个通常兼作“字段变化” X in subject Y" - 观察者将简单地忽略对字段的更改!= X)。