思想:不改变原来代码的情况下,扩展程序功能
意图:
为其他对象提供一种代理以控制对这个对象的访问。
适用性:
在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用Proxy模式。下面是一些可以使用Proxy 模式常见情况:
- 远程代理(Remote Proxy )为一个对象在不同的地址空间提供局部代表。
2 )虚代理(Virtual Proxy )根据需要创建开销很大的对象。
- 保护代理(Protection Proxy )控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
4)智能指引(Smart Reference )取代了简单的指针,它在访问对象时执行一些附加操作。
案例一
'''
Proxy
'''
import time
class SalesManager:
def work(self):
print("Sales Manager working...")
def talk(self):
print("Sales Manager ready to talk")
class Proxy:
def __init__(self):
self.busy = 'No'
self.sales = None
def work(self):
print("Proxy checking for Sales Manager availability")
if self.busy == 'No':
self.sales = SalesManager()
time.sleep(2)
self.sales.talk()
else:
time.sleep(2)
print("Sales Manager is busy")
if __name__ == '__main__':
p = Proxy()
p.work()
p.busy = 'Yes'
p.work()
案例二:以增加权限验证为例,只有管理员的身份可以发表文章,非管理员身份不能发表文章
# 先创建一个文章类
class Article:
pass
# 再创建一个发表文章类
class PublishArticle:
def open(self):
print('open database')
def save(self):
print('save article')
def close(self):
print('close database')
# 假如不添加代理模式,则任何一个人都有发表文章的权限
publist_article=PublishArticle()
publist_article.open()
publist_article.save()
publist_article.close()
# 运行结果
# open database
# save article
# close database
import random
# 而实际项目开发过程中,对于类似的操作都需要进行权限验证,此时在不修改原来代码的基础上,可以使用代理模式,进行权限验证
class Proxy:
def __init__(self,publish_article,user_id):
# publish_article是发表文章的对象(被代理对象),一个是用户的id
self.publish_article=publish_article
self.user_id=user_id
# 定义一个验证是否是管理员的方法
def is_admin(self):
# 根据已经传入的user_id在数据库中查找该用户的身份是否为管理员admin,返回True或False
# 这里就模拟一个随机返回,返回值为真或假
return random.choice([True,False])
# 根据已经验证的是否为管理员,做出不同的操作
def publish_article_new(self):
# 如果是管理员
if self.is_admin():
# 被代理对象的发表文章的方法可以正常执行
self.publish_article.save()
else:
print("你不是管理员,没有发表文章的权限")
# 如果调用了该类中不存在的方法,则会返回 self.publish_article所有的方法
def __getattr__(self, item):
return getattr(self.publish_article,item)
proxy=Proxy(PublishArticle(),'001')
proxy.open()
proxy.publish_article_new()
proxy.close()
'''
# 因为这里是否是管理员,是系统随机的,所以可能会有如下结果
open database
save article
close database
或者:
open database
你不是管理员,没有发表文章的权限
close database
'''
代理模式与装饰器模式的相同点:
都是为了再不改变原来代码的情况下,为程序扩展功能。