Django 的 cache 缓存机制,包含了一些代理设计模式(代理了但没完全代理,多此一举)。
通过实现一个CacheHandler的manager类,来实现多缓存后端的统一管理和调用,避免到处实例使用。
缓存的目的就是为了提高系统的性能.
通过一个外部 Proxy 来访问真实 cache 对象的属性和方法。
这个ConnectionProxy可以学习他用到的魔法方法,但本质上和设计模式没太多关系。
整个django项目里一共出现两次,一次在cache中作为default cache的入口,一次在db中作为defult db的入口
# 没啥用,直接用caches['default']代替即可
class ConnectionProxy:
"""Proxy for accessing a connection object's attributes."""
def __init__(self, connections, alias):
self.__dict__["_connections"] = connections
self.__dict__["_alias"] = alias
# 重写__getattr__方法, 使得ConnectionProxy可以像访问真实的connection对象一样访问属性和方法
def __getattr__(self, item):
return getattr(self._connections[self._alias], item)
# 重写__setattr__方法, 使得ConnectionProxy可以像访问真实的connection对象一样设置属性和方法
def __setattr__(self, name, value):
return setattr(self._connections[self._alias], name, value)
# 重写__delattr__方法, 使得ConnectionProxy可以像访问真实的connection对象一样删除属性和方法
def __delattr__(self, name):
return delattr(self._connections[self._alias], name)
# 重写__contains__方法, 使得ConnectionProxy可以使用 `key in ConnectionProxy`的语法来判断key是否存在于缓存中, 实际实现在BaseCache的各个子类中实现
def __contains__(self, key):
return key in self._connections[self._alias]
# 重写__eq__方法, 使得ConnectionProxy可以使用 `ConnectionProxy == other`的语法来判断两个ConnectionProxy是否指向同一个缓存对象, 实际实现在BaseCache的各个子类中实现
# 其实可以用total_ordering装饰器来实现__eq__方法, 但是为了保持一致性, 这里还是自己实现
def __eq__(self, other):
return self._connections[self._alias] == other
所以可以参照 Django 的做法,使用一个名字对象来代替默认值参数。
# 通常做法
def get_backend_timeout(self, timeout=None):
"""
Return the timeout value usable by this backend based upon the provided
"""
if timeout is None:
timeout = self.default_timeout
return timeout
# 改进做法
DEFAULT_TIMEOUT = object() # python模块单例
def get_backend_timeout(self, timeout=DEFAULT_TIMEOUT):
"""
Return the timeout value usable by this backend based upon the provided
"""
if timeout is DEFAULT_TIMEOUT: # is 比较内存地址
timeout = self.default_timeout
return timeout
实现 contains 方法可以改变in操作的结果
def __contains__(self, key):
"""
Return True if the key is in the cache and has not expired.
"""
# This is a separate method, rather than just a copy of has_key(),
# so that it always has the same functionality as has_key(), even
# if a subclass overrides it.
return self.has_key(key)
其他部分就是 BaseCache 的子类了,用对应的 client 实现缓存的方法。