关于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 面向对象编程》