【问题标题】:Notifying container object: best practices通知容器对象:最佳实践
【发布时间】:2010-10-22 13:30:56
【问题描述】:

我有两个类:Account 和 Operator。帐户包含操作员列表。现在,每当操作员(在列表中)收到消息时,我想通知 Account 对象也执行一些业务逻辑。

关于如何实现这一点,我想到了三种替代方案:

1) 在 Operator 中持有对容器 [Account] 对象的引用并直接调用方法。由于循环引用,并不是绝对好。

2) 使用事件。据我所知,Python 中没有内置的事件处理机制。所以,这个实现起来有点棘手。

3) 不要直接向 Operator 发送消息。取而代之的是,只操作 Accounts,并在其中内部操作处理程序操作员。这有点限制,因为在这种情况下,我无法传递对运算符的引用。

我想知道从架构的角度来看哪种方法最有利。您通常如何处理这项任务?

如果你能指出 Python 中的 sn-ps 那就太好了。

【问题讨论】:

    标签: python architecture containers notifications


    【解决方案1】:
    >>> class Account(object):
    ...     def notify(self):
    ...         print "Account notified"
    ...
    >>> class Operator(object):
    ...     def __init__(self, notifier):
    ...         self.notifier = notifier
    ...
    >>> A = Account()
    >>> O = Operator(A.notify)
    >>> O.notifier()
    Account notified
    >>> import gc
    >>> gc.garbage
    []
    >>> del A
    >>> del O
    >>> gc.garbage
    []
    

    关于实例方法,您可能不知道的一件事是,当使用点语法查找时,它们是绑定的。换句话说,A.notify 自动将 notify 的 self 参数绑定到 A。然后您可以持有对该函数的引用,而不会产生无法回收的垃圾。

    最后,您可以随时使用Kamaelia 处理这类事情。

    【讨论】:

    • 哇,感谢代码 sn-p 和非常清晰的解释。非常有趣的方法。
    【解决方案2】:

    你想多了。严重地。 Python 不是 C++;您的担忧在 Python 中不是问题。只需写出对您的问题领域有意义的内容即可。

    “由于循环引用,不是绝对好。”

    为什么不呢?循环在这里根本无关紧要。双向关系是很棒的事情。使用它们。 Python 垃圾可以很好地收集它们,而无需您考虑。

    您对相互(双向)关系有什么可能的问题?

    "...只操作帐户,在它们内部,在内部,处理程序操作符。这个有点限制,因为在这种情况下我不能传递对操作符的引用。 "

    什么?你的操作符是 Python 对象,传递你想要的一切。所有 Python 对象(实际上)都是引用,不要担心。

    您在操作 Operator 对象时可能遇到什么问题?

    【讨论】:

    • +1 - 只要您使用 Python 2.5 并且不定义 del 方法,循环引用就不再是什么大问题了。
    • @Jason Baker:7 年来大量使用 Python,从未定义过 del 方法。双向关系从来没有问题,定期使用它们。回到 2.2,它们一直运行良好。
    • 好吧,不知道它会追踪所有的循环引用。但是,如果我确实定义了 del 方法(无论出于何种原因)怎么办?我仍然需要手动跟踪它们,对吧?
    • @S.Lott 你是对的关于过度思考。有时我倾向于想太多;)
    • @seasonedcoder:您对 del 方法没有用处。没有任何。如果您认为您需要它 (a) 您做错了什么,并且 (b) 将您的目标和代码作为单独的问题发布,以便我们可以告诉您您做错了什么。
    【解决方案3】:

    Web 上到处都有观察者模式 sn-ps。可靠代码的良好来源是活动状态,例如:

    http://code.activestate.com/recipes/131499/

    【讨论】:

      【解决方案4】:

      我会为此使用事件处理。您不必自己实现它——我使用pydispatcher 来处理这种事件,而且它总是工作得很好(它在内部使用弱引用,以避免循环引用问题)。

      另外,如果您使用的是 gui 框架,您可能已经有一个可以挂钩的事件框架,例如 PyQt 有信号和插槽。

      【讨论】:

      • +1 表示 pydispatcher 及其亲属。它使用简单,旨在准确解决您所描述的情况。它以某种方式解耦对象,如果需要,您也可以将 Operator 连接到其他容器中
      【解决方案5】:

      观察者模式没有“一刀切”的解决方案。但通常,最好定义一个 EventManager 对象,感兴趣的各方可以在其中注册某些事件并在这些事件发生时发布这些事件。它只是创建了更少的依赖关系。

      请注意,您需要使用全局 EventManager 实例,这在测试期间或从一般 OO 的角度来看(它是一个全局变量)可能会出现问题。我强烈建议不要一直传递 EventManager,因为这会使你的代码混乱。

      在我自己的代码中,注册事件的“关键”是事件的类。 EventManager 使用字典(事件类 -> 观察者列表)来了解哪个事件去往何处。在通知代码中,您可以使用dict.get(event.__class__, ()) 查找您的听众。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-03-22
        • 2011-07-12
        • 2011-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-19
        相关资源
        最近更新 更多