python 观察者模式

所谓的观察者模式, 也就是一个对象发生变化时, 观察者能及时得到通知并更新.

我们可以通过如下代码来理解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
from abc import ABC, abstractmethod

class Subject(ABC):
"""被观察的数据基类
"""
def __init__(self):
# 保存观察者引用
self._observers = []

def attach(self, observer):
# 添加观察者
if observer not in self._observers:
self._observers.append(observer)

def detach(self, observer):
# 删除观察者
try:
self._observers.remove(observer)
except ValueError:
pass

def notify(self, modifier=None):
# 通知观察者, 在数据更改时调用
for observer in self._observers:
if observer != modifier:
observer.update(self)


class Data(Subject):
"""被观察的数据
"""
def __init__(self,name=''):
# 初始化基类
super(Data, self).__init__()
self.name = name
self._data = 0

@property
def data(self):
# 读取数值, 不做其他操作
return self._data

@data.setter
def data(self, value):
# 数值更改时触发 notify 方法
self._data = value
self.notify()

def __repr__(self):
# 数据展示, 没定义 __str__ 时自动用 __repr__
return 'Data(name={}, data={})'.format(self.name, self.data)


class Observer(ABC):
"""观察者基类, 可不定义, 子类符合规范即可
"""
@abstractmethod
def update(self, subject):
pass


class HexViewer(Observer):
"""观察者子类1, 和2实现一致
"""
def update(self, subject):
print('at {}, observing {})'.format(self.__class__.__name__, subject))


class DecimalViewer(Observer):

def update(self, subject):
print('at {}, observing {})'.format(self.__class__.__name__, subject))

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>>> d1 = Data('data1')
>>> d2 = Data('data2')
>>> v1 = HexViewer()
>>> v2 = DecimalViewer()
>>> d1
Data(name=data1, data=0)
>>> d1.attach(v1)
>>> d1.attach(v2)
>>> d2
Data(name=data2, data=0)
>>> d2.attach(v2)
>>> d1.data = 2
at HexViewer, observing Data(name=data1, data=2))
at DecimalViewer, observing Data(name=data1, data=2))
>>> d1
Data(name=data1, data=2)
>>> d2.data
0
>>> d2.data = 3
at DecimalViewer, observing Data(name=data2, data=3))

最需要关注的就是被观察对象的基类定义的 notify 方法, 在实际使用时流程如下:

  1. 数据绑定观察者
  2. 数据更改时调用来自基类的 notify 方法
  3. notify 方法调用所有观察者的 update 方法实现观察者的感知.