观察者模式

2019-04-13  本文已影响0人  井底蛙蛙呱呱呱
观察者模式在状态监测和事件处理等场景中是非常有用的。这种模式确保一个核心对象可以由一组未知并可能正在扩展的‘观察者’对象来监控。一旦核心对象的某个值发生变化各个观察者在核心对象发生变化时,有可能会处理不同的任务;核心对象不知道也不关心这些任务是什么,通常观察者也同样不知道、不关心其他的观察者正在做什么。下图是他在UML中的表现形式: 观察者模式
关于UML图中各个图标的意思

观察者实例

观察者模式在一个冗余备份系统中是非常有用的。我们可以编写一个核心对象来维持一些特定的值,然后用一个或多个观察者来创建该对象的一系列副本。例如,这些副本可能储存在数据库、远程主机或者一个本地文件夹中。让我们来实现这个核心对象的一些属性:

class Inventory(object):
    def __init__(self):
        self.observers = []
        self._product = None
        self._quantity = 0

    def attach(self, observer):
        self.observers.append(observer)
        
    @property
    def product(self):
        return self._product
    
    @product.setter
    def product(self, value):
        self._product = value
        self._update_observers()
        
    @property
    def quantity(self):
        return self._quantity
    
    @quantity.setter
    def quantity(self, value):
        self._quantity = value
        self._update_observers()
    
    def _update_observers(self):
        for observer in self.observers:
            observer()

这个对象有两个属性,对其执行赋值,便调用_update_observers方法。该方法所做的全部工作就是对所有可用的观察者进行遍历,好让他们知道发生了一些变化。在这里,我们直接调用观察者对象,而这个对象必须实现__call__函数来处理变化。这在许多面向对象的编程语言中是不可能的,但是在Python中,这是一种让我们的代码更具有可读性的捷径。

现在让我们实现一个简单的观察者对象,他只是将一些状态打印到控制台。

class ConsoleObserver(object):
    def __init__(self, inventory):
        self.inventory = inventory
    
    def __call__(self):
        print(self.inventory.product)
        print(self.inventory.quantity)

这里没什么特别激动的事情:在初始化函数中设置被观测的对象,以及当观察者被调用时,我们会做一些事。我们现在来对观察者进行简单的测试:

i = Inventory()
c = ConsoleObserver(i)
i.attach(c)
i.product = 'Widget'
i.quantity = 5

# 输出:
Widget
0
Widget
5

将观察者附加到库存对象后,每当我们改变这两个被观察者属性时,观察者就会调用并执行动作。我们甚至可以添加两个不同的观察者实例:

i = Inventory()
c1 = ConsoleObserver(i)
c2 = ConsoleObserver(i)
i.attach(c1)
i.attach(c2)
i.product = 'Widget'
i.quantity = 5

# 输出:
Widget
0
Widget
0
Widget
5
Widget
5

这一次我们改变产品时,会出现两组输出,每个观察者各一个。这里的关键理念是,我们可以很容易的添加两个完全不同类型的观察者,从而将数据同时备份至文件、数据库或者互联网应用中。

观察者模式将正在被观察者的代码和执行观察的代码分离。如果我们不使用模式,我们就必须要在每个属性中添加代码来处理可能出现的情况,例如登录到控制台,更新一个数据库或文件等。每个人物的代码都会被观察的对象混合在一起。想要维护他们将会是一个噩梦,在日后添加新的监控功能也会变得非常痛苦。

参考:
《Python3 面向对象编程》

上一篇 下一篇

猜你喜欢

热点阅读