用实例理解设计模式——代理模式(Python版)
代理模式:为其他对象提供一种代理以控制对这个对象的访问。
在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式分为:
- 静态代理
- 动态代理
由下面三部分组成:
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
静态代理
在程序运行前,就已经确定代理类和委托类的关系的代理方式,被称为静态代理。
例:小明请律师进行诉讼
诉讼流程可抽象为ILawsuit类,如下:
import abc
class ILawsuit(metaclass=abc.ABCMeta):
@abc.abstractmethod
def submit(self): # 提交申请
pass
@abc.abstractmethod
def burden(self): # 进行举证
pass
@abc.abstractmethod
def defend(self): # 开始辩护
pass
@abc.abstractmethod
def finish(self): # 诉讼完成
pass
小明为具体诉讼人,可写为Litigant类,如下:
class Litigant(ILawsuit): # 继承于ILawsuit
def __init__(self, name):
self.name = name
def submit(self):
print(f'{self.name}申请仲裁!')
def burden(self):
print('证据如下:XXXXXX')
def defend(self):
print('辩护过程:XXXXXX')
def finish(self):
print('诉讼结果如下:XXXXXX')
律师可写为Lawyer类,如下:
class Lawyer(ILawsuit): # 继承于ILawsuit
def __init__(self, litigant):
self.litigant = litigant # 具体诉讼人
def submit(self):
self.litigant.submit()
def burden(self):
self.litigant.burden()
def defend(self):
self.litigant.defend()
def finish(self):
self.litigant.finish()
诉讼过程,可表示为:
if __name__ == '__main__':
xiaoming = Litigant('小明')
lawyer = Lawyer(xiaoming)
lawyer.submit() # 律师提交诉讼申请
lawyer.burden() # 律师进行举证
lawyer.defend() # 律师替小明辩护
lawyer.finish() # 完成诉讼
# 输出结果
小明申请仲裁!
证据如下:XXXXXX
辩护过程:XXXXXX
诉讼结果如下:XXXXXX
静态代理的优缺点
优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。
缺点:代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
动态代理
代理类在程序运行时创建的代理方式被称为 动态代理。
也就是说,这种情况下,代理类并不是在代码中定义的,而是在运行时根据我们在代码中的指示动态生成的。
同样,我们举例说明:
通常我们调用REST API通常可能是这样的:
import urllib
import json
def fetch_resource(resource_id):
opener = urllib.urlopen('http://remote.server/api/resource/' + resource_id)
if opener.code != 200:
raise RuntimeError('invalid return code!')
content = opener.read()
try:
return json.loads(content)
except ValueError:
return content
对于每一个REST操作,都会有类似的代码。差别仅在于API的地址和HTTP method(GET、POST、等)。此时,可以引入一个GetProxy,可以代替我们实现这些繁杂的工作。
import urllib
import json
class GetProxy(object):
def __getattr__(self, api_path):
def _rest_fetch(*paras):
opener = urllib.urlopen('http://remote.server/api/' + api_path + '/' + '/'.join(resource_id))
if opener.code != 200:
raise RuntimeError('invalid return code!')
content = opener.read()
try:
return json.loads(content)
except ValueError:
return content
return _rest_fetch
此时,新的调用方式如下:
proxy = GetProxy()
# 调用API
proxy.user(123) # http://remote.server/api/user/123
proxy.resource('switch', 456) # http://remote.server/api/resource/switch/456
可见,通过动态代理,极大简化了调用过程。
相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。
参考
http://adolph.cc/15712984956484.html
https://blog.zhangyu.so/python/2016/02/24/design-patterns-of-python-proxy/

用实例理解设计模式——代理模式(Python版)的更多相关文章
- 浅谈Python设计模式 - 代理模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 一.在某些应用中,我们想要在访问某个对象之前执行一个或者多个重要的操作,例如,访 ...
- PHP设计模式-代理模式
概念理解: 代理模式,是对简单处理程序(或指针)的增强,用于引用一个对象:这个指针被代理对象取代,代理对象位于客户端和真实程序之间,指针有一个可被多个目标利用的钩子. 参与者: client(参与者) ...
- C++设计模式——代理模式
前言 青春总是那样,逝去了才开始回味:大学生活也是在不经意间就溜走了,现在上班的时候,偶尔还会怀念大学时,大家在一起玩游戏的时光.大学喜欢玩游戏,但是可悲的校园网,速度能把人逼疯了:还好,后来搞了一个 ...
- Java设计模式—代理模式
代理模式(Proxy Pattern)也叫做委托模式,是一个使用率非常高的模式. 定义如下: 为其他对象提供一种代理以控制对这个对象的访问. 个人理解: 代理模式将原类进行封装, ...
- Java设计模式-代理模式之动态代理(附源代码分析)
Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...
- 9. 星际争霸之php设计模式--代理模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- Java 之 设计模式——代理模式
设计模式——代理模式 一.概述 1.代理模式 (1)真实对象:被代理的对象 (2)代理对象:代理真实对象的 (3)代理模式:代理对象代理真实对象,达到增强真实对象功能的目的 二.实现方式 1.静态代理 ...
- Python设计模式——代理模式(Proxy)
书中的例子是:男A喜欢女A,但是不敢向其表白,所以委托男B为代理,代他送礼物给女A,实现这个需求的重点是,男A和女A是不互相直接接触的,都是通过代理男B,实现间接接触. #encoding=utf-8 ...
- 设计模式--代理模式(C++版)
一:代理模式简介 专业版描述:为其他对象提供一种代理以控制对这个对象的访问. 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 戏剧性描述: ...
随机推荐
- 【[Offer收割]编程练习赛9 D】 矩阵填数
[题目链接]:http://hihocoder.com/problemset/problem/1480 [题意] [题解] 这是一道杨氏矩阵的题; 一个固定形状的杨氏矩阵的种类个数; 等于这个杨氏矩阵 ...
- H3C用Telnet登录
- @noi.ac - 491@ explore
目录 @description@ @solution@ @accepted code@ @details@ @description@ 最近有一个巨大的古代地下遗迹在比特镇被发现.这个地下遗迹的俯视图 ...
- 如何把thinkphp 的url改为.html
ThinkPHP支持伪静态URL设置,可以通过设置URL_HTML_SUFFIX参数随意在URL的最后增加你想要的静态后缀,而不会影响当前操作的正常执行.例如,我们设置'URL_HTML_SUFFIX ...
- ipykernel_launcher.py: error: unrecognized arguments: -f /Users/apple/Library/Jupyter/runtime/kernel
当在jupyter下使用parser.parse_args()出错则改换为parser.parse_known_args()[0]其效用是差不多的,至于为什么出现错误,我也不知道…
- div盒子或者图片并排居中
要使div总是找不到原因居中很简单,float和display都可以实现,float就不说了,这里说一下display:line-block,比如四个或者多个div盒子,明明设置好了宽度后,总有一个上 ...
- WOE:信用评分卡模型中的变量离散化方法(生存分析)
WOE:信用评分卡模型中的变量离散化方法 2016-03-21 生存分析 在做回归模型时,因临床需要常常需要对连续性的变量离散化,诸如年龄,分为老.中.青三组,一般的做法是ROC或者X-tile等等. ...
- ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Read timed out.
ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Read timed out.You a ...
- 2018-12-14-恢复-U-盘隐藏文件夹
title author date CreateTime categories 恢复 U 盘隐藏文件夹 lindexi 2018-12-14 19:24:56 +0800 2018-12-14 19: ...
- linux一些重要数据结构
如同你想象的, 注册设备编号仅仅是驱动代码必须进行的诸多任务中的第一个. 我们将很 快看到其他重要的驱动组件, 但首先需要涉及一个别的. 大部分的基础性的驱动操作包括 3 个重要的内核数据结构, 称为 ...