我们都知道observer pattern:您有一个主题,可以通知和更新其状态更改的观察者列表。现在假设您要观察的主题是一个容器,并且您想观察容器本身,即元素的元素添加和删除,以及所包含的元素,即容器元素的状态更新。
当在容器中存储大量对象时,如何实现更新机制以便在元素插入和删除方面快速完成?特别是,
例如,如果您的容器是一个链表,则可以在固定时间内插入元素。如果m个观察者必须遍历包含n个元素的列表,则更新将花费O(n * m)个预期时间。
如果您的容器是一个数组,那么更改元素将花费固定时间,如果传递元素的索引,则更新m个观察者将花费O(m),如果观察者必须遍历该数组,则更新O(n * m)会花费O(n * m)。
如果有帮助,请考虑以下示例:
示例1.您正在编写一个操作系统。您要观察的主题是文件系统及其文件。您的视图是文件浏览器,索引器和其他应用程序。添加,删除或修改文件时,您想更新观察者。
示例2.您正在编写一个地址簿应用程序,该应用程序应该能够处理纽约大小的城市。您想观察的主题是您的记录的容器(带有地址,电话号码,电子邮件...的人)。观察者是几个视图,当您添加,删除或修改记录时,这些视图应自动更新。 (一个人可能会看到一个视图,其中包含一个生活在第53位的人的列表,另一个视图是在地图上为姓氏为Doe的每个人绘制点)。
如何处理删除完整的目录子树或将“53rd St”重命名为“Dijkstra St”的情况?
最佳答案
您必须以某种方式将容器变成主题。
这里的主要问题是找到一种有效的方法来注意到更改。在大多数情况下,遇到此问题是因为要观察的事物没有提供有效的通知机制(可能是因为编写观察者时并未发明观察者的设计模式)。
[编辑]因为您要求一种有效的方法,所以一般的回答是“取决于情况”。设计模式没有“一刀切”的解决方案。它们是解决问题的一般规则。在特定情况下,您需要解决如何在特定情况下实施规则。
通常,如果您的观察者需要识别微小的更改(即属性更改或添加元素),则通知消息应包含足够的信息以使他们可以有效地做到这一点。因此,如果您有一个很大的列表和一个插入,请发送该列表和新元素的索引以及“插入的项目”。
至于属性更改,有两种解决方案。一种是将观察者添加到列表中的每个元素。这可能很慢并且需要大量RAM,但是这意味着您可以在同一列表中添加几种类型。
或者,您可以具有“在列表服务中修改项目”。这意味着禁止直接更改项目,您必须始终使用该服务。然后,该服务可以作为主题,并发送带有项目,旧值和更改后的值以及列表中的索引的通知。
[EDIT2]一般规则是收集有关更改的尽可能多的信息,并将其传递给观察者。但这确实取决于您的特定问题。假设观察者坐在远程机器上。在这种情况下,没有有效的方法将整个列表发送给它。您只能将其发送为“已插入X项”,希望这样就足够了。如果容器没有办法注意到更改(例如,网站上的新网页),则容器必须一次又一次遍历整个站点以查找更改,然后可以有效地告知观察者。
同样,细节确实取决于具体情况。 Google运行着数千个网络蜘蛛,每小时都会访问数百万个网页。长期以来,这是“有效的”(如“唯一的方式”)。不久前,实施了“站点地图”协议,该协议允许管理员将其网站变成可以告知Google观察者更改的主题。
因此,除非您能给出更具体的示例,否则您将无法给出更具体的答案。使用设计模式时,您需要坐下来解决一个真正的问题并动脑筋。
[EDIT3]以下是使用观察者模式的几个示例:
关于design-patterns - 如果主题是一个巨大的容器,您如何有效地实现观察者模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/955155/