观察者模式,无需多线程完成数据监听

观察者模式,无需多线程完成数据监听

大家好,我们今天来了解一个新的设计模式——观察者模式。

观察者模式的思路很简单,它被广泛地用在各种数据监控上。很多时候我们希望监听某个数据的变化,希望一旦获悉它的变化之后立即采取一些举措。按照常规的操作,我们需要开启额外的线程来进行监听。但是开启线程一则非常麻烦,二则需要带来额外的开销,我们今天介绍的观察者模式就可以在无需多余开销的基础上完成这个功能。

观察者

在观察者模式当中,整个运行流和常规的操作相反,我们并不是用一些程序去监听数据的变化。相反而是当数据发生变化的时候,我们去通知对应的监听器数据产生了变化。好处我们前面也说过了,可以避免多余的开销。

首先,我们来实现两个监听器。也就是当数据发生变化之后会触发这两个监听器。在这个设计模式当中,监听器被命名为viewer,这里的观察不是一种主动的观察而是一种被动地接收通知。也许是起名的人想不出更好的名字来吧,其实我觉得应该叫做receiver更好。

class IncreaseViewer:

    def __init__(self):
        self.data = 0

    def update(self, subject):
        # 判断是否增加
        if subject.data > self.data:
            print('Increased: Subject {} data increased to {}'.format(subject.name, subject.data))
            self.data = subject.data

class DeclineViewer:

    def __init__(self):
        self.data = 0

    def update(self, subject):
        # 判断是否减少
        if subject.data < self.data:
        print('Decreased: Subject %s data decreased to %d' % (subject.name, subject.data))
        self.data = subject.data

数据

观察者的代码应该很好理解,理解了观察者类之后,我们再来看看数据类。

数据的类其实也很简单,我们只需要设计一个功能,让它可以在数据发生赋值操作的时候去通知一下观察者就可以了。我们都知道在Python当中,赋值操作是没办法直接感知的,但是类当中的成员发生变化的时候,我们是可以通过@property装饰器来进行修饰的。

所以我们就利用这一点来实现数据这个类,如果大家熟悉@property注解的话,也非常简单。

class Data(Subject):

    def __init__(self, name=''):
        Subject.__init__(self)
        self.name = name
        self._data = 0

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, data):
        self._data = data
        # 关键
        self.notify()

大家看到了data这个方法当中的self.notify了吗?这个就是通知函数,所以就是当Data这个类当中的data成员发生变化的时候,我们执行通知操作,去通知观察者执行。

管理观察者

现在我们观察者实现好了,数据类也有了,剩下的就是把这两者连通起来了。我们当然也可以简单粗暴地用代码实现,但是比较好的做法是对数据和观察者之间的联系做一个简单的管理。因为可能不同的数据需要的观察者不一样,我们并不能简单粗暴地一概而论。

其实管理观察者也不需要太复杂,只需要用面向对象的思路对list进行一个简单的封装即可。


class Subject:

    def __init__(self):
        self._observer = []

    def attach(self, observer):
        if observer not in self._observer:
            self._observer.append(observer)

    def detach(self, observer):
        try:
            self._observer.remove(observer)
        except ValueError:
            pass

    def notify(self, modifier=None):
        for observer in self._observer:
            if modifier != observer:
                observer.update(self)

attach表示关联,也就是给数据关联上观察者,detach表示解除关联,notify自然就是通知了。其实也就是用一个循环遍历一下所有的观察者,然后执行一下对应的update函数就可以了。当然这里如果观察者很多或者是运行效率不高的话,可以考虑一下使用多线程来并发执行。

这里为了简化逻辑,我们把Subject类做成了Data类的父类。这样某种程度上相当于解耦了观察者和数据,我们以后无论是对哪部分逻辑进行修改或者是优化都不会影响另外两方。整个代码不过50行,可以说是非常简便了,不仅是Python,对于其他支出多态的语言来说,这个设计模式也是同样适用的。

到这里关于观察者模式就介绍完了,今天的文章就到这里。衷心祝愿大家每天都有所收获。如果还喜欢今天的内容的话,请来一个三连支持吧~(点赞、在看、转发)

上一篇:git_svn提交模板


下一篇:Abaqus中的网格划分(Mesh commands)