今天想到给以前写的东西增加缓存支持,每次数据库发生变化之后主动的去修改缓存。当然最笨的方法就是在每次更新数据库的代码后面写一段更新缓存的代码,我们能不能在数据库被更新之后对外发一个信号呢,更新缓存的函数收到这个信号就知道数据库发生了变化。

这个在django中其实已经有了实现,就是siginal,用法大致的这样的

def my_callback(sender, **kwargs):
    print("Request finished!")

from django.core.signals import request_finished

request_finished.connect(my_callback)

这个其实就是经典的观察者模式的实现。

http://dongweiming.github.io/python-observer.html 有一段代码,我认为很好,直接贴过来了(其实后来发现原版在 https://github.com/faif/python-patterns/blob/master/observer.py )

# 这个是观察者基类
class Subject(object):
    def __init__(self):
        self._observers = []

    # 添加依赖的对象
    def attach(self, observer):
        if not observer 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 modifier != observer:
                observer.update(self)


# 观察者类
class Data(Subject):
    def __init__(self, name=''):
        super(Data, self).__init__()
        self.name = name
        self._data = 0

    # python2.6新增的写法,获取属性为property,设置属性为(假设属性名字为x)@x.setter,删除为@x.deleter
    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, value):
        self._data = value
        self.notify()

# 这里有2个被观察者,也就是依赖的对象,每次Data有改变,这2个view都会变动
class HexViewer(object):
    def update(self, subject):
        print 'HexViewer: Subject %s has data 0x%x' % (subject.name, subject.data)

class DecimalViewer(object):
    def update(self, subject):
        print 'DecimalViewer: Subject %s has data %d' % (subject.name, subject.data)


if __name__ == '__main__':

    data1 = Data('Data 1')
    data2 = Data('Data 2')
    view1 = DecimalViewer()
    view2 = HexViewer()
    data1.attach(view1)
    data1.attach(view2)
    data2.attach(view2)
    data2.attach(view1)

    print "Setting Data 1 = 10"
    data1.data = 10
    print "Setting Data 2 = 15"
    data2.data = 15
    print "Setting Data 1 = 3"
    data1.data = 3
    print "Setting Data 2 = 5"
    data2.data = 5
    print "Update data1's view2 Because view1 is be filtered"
    data1.notify(modifier=view1)  
    print "Detach HexViewer from data1 and data2."
    data1.detach(view2)
    data2.detach(view2)
    print "Setting Data 1 = 10"
    data1.data = 10
    print "Setting Data 2 = 15"
    data2.data = 15

输出结果是

Setting Data 1 = 10
DecimalViewer: Subject Data 1 has data 10
HexViewer: Subject Data 1 has data 0xa
Setting Data 2 = 15
HexViewer: Subject Data 2 has data 0xf
DecimalViewer: Subject Data 2 has data 15
Setting Data 1 = 3
DecimalViewer: Subject Data 1 has data 3
HexViewer: Subject Data 1 has data 0x3
Setting Data 2 = 5
HexViewer: Subject Data 2 has data 0x5
DecimalViewer: Subject Data 2 has data 5
Update data1's view2 Because view1 is be filtered
HexViewer: Subject Data 1 has data 0x3
Detach HexViewer from data1 and data2.
Setting Data 1 = 10
DecimalViewer: Subject Data 1 has data 10
Setting Data 2 = 15
DecimalViewer: Subject Data 2 has data 15
[Finished in 0.1s]

如果要像django那样直接传递一个类而不是类实例,我们可以使用classmethod或者staticmethod,仿照http://www.the5fire.com/python-observer.html 我自己写了一个

#event.py
class Event(object):
    _observers = []

    def __init__(self, subject):
        self.subject = subject
 
    @classmethod
    def register(cls, observer):
        if observer not in cls._observers:
            cls._observers.append(observer)
 
    @classmethod
    def unregister(cls, observer):
        if observer in cls._observers:
            cls._observers.remove(observer)
 
    @classmethod
    def notify(cls, subject):
        event = cls(subject)
        for observer in cls._observers:
            observer(event)

#process.py
from event import Event


class Data(object):
    def __init__(self, value):
        self.value = value
        Event.notify("set value")


#main.py
from event import Event
from process import Data


def log(event):
    print "log", event.subject


def log1(event):
    print "log1", event.subject


Event.register(log)
Event.register(log1)
Data(123)

Event.unregister(log1)
Data(456)

输出是

log set value
log1 set value
log set value

是不是更像django里面的用法了呢~