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
import time

# 缓存字典
cache = dict()


class Image:
"""图片对象, 以延时返回地址模拟网络请求图片的过程"""
def __init__(self, name):
self.name = name

@property
def url(self):
time.sleep(2)
return 'http://www.baidu.com/favicon.ico'


class Page:
"""调用图片"""
def __init__(self, image):
self.image = image

def render(self):
print('render:', self.image.url)


class ImageProxy(object):
"""图片代理"""
def __init__(self, image):
self.image = image

@property
def url(self):
"""与原接口一致"""
# 先从缓存提取
t0 = time.time()
addr = cache.get(self.image.name)
if not addr:
# 未找到时请求并存入缓存
print('not found in cache')
addr = self.image.url
cache[self.image.name] = addr
else:
print('found in cache')
print('time cost:', time.time() - t0)
return addr


if __name__ == "__main__":
img = Image('ico')
proxy = ImageProxy(img)
page = Page(proxy)
page.render()
print()
page.render()

执行:

1
2
3
4
5
6
7
not found in cache
time cost: 2.0028703212738037
render: http://www.baidu.com/favicon.ico

found in cache
time cost: 0.0
render: http://www.baidu.com/favicon.ico

可以看到第一次请求时未找到, 用时两秒请求, 存入缓存后直接从缓存提取, 耗时忽略不计.

Page 所持有的对象从 Image 变成了 ImageProxy, 但 Page 和 Image 本身的代码并未改变.
而缓存存入和提取操作由 ImageProxy 完全代劳.

代理对象和真实的对象之间都实现了共同的接口, 这使我们可以在不改变原接口情况下, 使用真实对象的地方都可以使用代理对象.
其次, 代理对象在客户端和真实对象之间直接起到了中介作用, 同时通过代理对象, 我们可以在将客户请求传递给真实对象之前做一些必要的预处理.