定义
- 为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
- 著名的代理模式例子为引用计数(英语:reference counting)指针对象。
当一个复杂对象的多份副本须存在时,代理模式可以结合享元模式以减少存储器用量。典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象。而作用在代理者的运算会转送到原本对象。一旦所有的代理者都不存在时,复杂对象会被移除。
代理模式的优点和应用场景
优点:
- 责任清晰:符合单一职责原则,使被代理对象实现真实业务逻辑,而非本职责的事务,交由代理完成;
- 扩展性高:面对被代理对象可能会有的改变,代理模式在不改变其对外接口的情况下,可以实现最大程度的扩展;
- 保证主题对象的处理逻辑:代理可以通过检查参数的方式,保证主题对象的处理逻辑输入在理想范围内。
应用场景:
- 针对某特定对象进行功能和增强性扩展。如IP防火墙,接口访问权限,远程访问代理,中间件等技术的应用;
- 对被代理对象进行保护。如大流量代理,安全代理等;
- 减轻被代理对象的负载。如接口分流等。
代理模式的缺点
- 可能会降低整体业务的处理效率和速度。
- 增加代码维护成本。
常见的代理模式的缺点
虚拟代理(VirtualPRoxy):推迟真正所需对象实例化时间.在需要真正的对象工作之前, 如果代理对象能够处理, 那么暂时不需要真正对象来处理.比如图片延迟加载,虚拟占位,通过延迟对象实例化来减缓系统资源的消耗
安全代理(ProtectionProxy):控制真实对象访问时的权限,比如某系统管理员A,利用终端访问令牌,访问终端代理,代理通过该令牌从数据库获得该令牌所拥有可操作的指令列表B,从而A每操作的一个指令都会检验是否存在于列表B,若存在则代理应用root或者其他用户 去执行该指令并将结果返回,该终端代理扮演的就是安全代理的角色。
智能代理(intelligent agent):是定期地收集信息或执行服务的程序,它不需要人工干预,具有高度智能性和自主学习性,可以根据用户定义的准则,主动地通过智能化代理服务器为用户搜集最感兴趣的信息,然后利用代理通信协议把加工过的信息按时推送给用户,并能推测出用户的意图,自主制订、调整和执行工作计划。比如定时任务Crontab
远程代理(Remote Proxy):本地服务通过网络请求远程服务。为了实现本地到远程的通信,我们需要实现网络通信,处理其中可能的异常。为良好的代码设计和可维护性,我们将网络通信部分隐藏起来,只暴露给本地服务一个接口,通过该接口即可访问远程服务提供的功能,而不必过多关心通信部分的细节。比如Django的ORM
数据懒加载
class _LazyProperty(object):
def __init__(self, func):
print(5*'*'+' _Lazy --> __init__ '+ 5*'*')
self.func = func
def __get__(self, instance, _cls):
print(5*'*'+' _Lazy --> __get__ (instance: %s _cls: %s) '%(str(instance), str(_cls)) + 5*'*')
val = self.func(instance)
setattr(instance, self.func.__name__, val)
return val
class UserInfo(object):
def __init__(self, _name):
print(5*'*'+' UserInfo --> __init__ '+ 5*'*')
self._name = None
@_LazyProperty
def name(self):
print(5*'*'+' UserInfo --> name <从数据库获取用户姓名> '+ 5*'*')
self._name = user_info_db_obj['name']
return self._name
if __name__ == '__main__':
# 模拟数据库
user_info_db_obj = dict(name='Lee')
# 获取用户信息
u = UserInfo('Lee')
print(u.name)
print(u.name)
print(u.name)
print(u.name)
# -*- coding: utf-8 -*-
from wsgiref.simple_server import make_server
from functools import wraps
def acl(func):
@wraps(func)
def wrap(_request, _response, *args, **kwargs):
try:
white_list = ['127.0.0.2']
_ip = _request['REMOTE_ADDR']
if _ip in white_list:
return func(_request, _response)
else:
raise IOError('access from %s is not in white'%(_ip))
except Exception as e:
return error_handle(str(e), _response)
return wrap
def error_handle(error_info, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return error_info
@acl
def some_handle(request, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return 'Query String Is %s' % str(request['QUERY_STRING'])
if __name__ == '__main__':
httpd = make_server('', 8000, some_handle)
print "Serving HTTP on port 8000..."
httpd.serve_forever()
access from 127.0.0.1 is not in white