聲明:本系列文章主要參考《精通Python設(shè)計模式》一書舵抹,并且參考一些資料苏携,結(jié)合自己的一些看法來總結(jié)而來贝室。
一、在某些應(yīng)用中畸裳,我們想要在訪問某個對象之前執(zhí)行一個或者多個重要的操作缰犁,例如,訪問敏感信息 -- 在允許用戶訪問敏感信息之前怖糊,我們希望確保用戶具備足夠的去權(quán)限帅容。同時在網(wǎng)絡(luò)訪問時,限制某些網(wǎng)絡(luò)的訪問等操作伍伤。
二丰嘉、把一個計算成本較高的對象的創(chuàng)建過程延遲到用戶首次真正使用它的時候才進(jìn)行。
以上的情況就可以使用 代理設(shè)計模式 嚷缭。
代理模式:因使用代理對象再訪問實際對象之前執(zhí)行重要操作而得其名。
示例:
之前想用《精通Python設(shè)計模式》中的示例來說明,但是發(fā)現(xiàn)很負(fù)責(zé)不太好理解阅爽,于是有了接下來的示例:阿里云:Python與設(shè)計模式 -代理模式路幸。
一、首先構(gòu)件一個網(wǎng)絡(luò)服務(wù)器:
#該服務(wù)器接受如下格式數(shù)據(jù)付翁,addr代表地址简肴,content代表接收的信息內(nèi)容
info_struct=dict()
info_struct["addr"]=10000
info_struct["content"]=""
class Server:
content=""
def recv(self,info):
pass
def send(self,info):
pass
def show(self):
pass
class infoServer(Server):
def recv(self,info):
self.content=info
return "recv OK!"
def send(self,info):
pass
def show(self):
print "SHOW:%s"%self.content
infoServer有接收和發(fā)送的功能,發(fā)送功能由于暫時用不到百侧,保留砰识。另外新加一個接口show,用來展示服務(wù)器接收的內(nèi)容佣渴。接收的數(shù)據(jù)格式必須如info_struct所示辫狼,服務(wù)器僅接受info_struct的content字段。
二辛润、若此時有需求膨处,該網(wǎng)絡(luò)服務(wù)器只允許部分網(wǎng)絡(luò)IP進(jìn)行訪問,那么需要設(shè)置白名單砂竖,該怎么做呢真椿?顯然可以有如下兩種方式:
①、修改Server結(jié)構(gòu)是個方法乎澄,即在進(jìn)入server時突硝,做一系列邏輯判斷。但這顯然不符合軟件設(shè)計原則中的單一職責(zé)原則置济。
②解恰、使用代理,即利用代理來進(jìn)行邏輯判定舟肉,若在白名單中修噪,則允許訪問,若不在則拒絕路媚。
class serverProxy:
pass
class infoServerProxy(serverProxy):
server=""
def __init__(self,server):
self.server=server
def recv(self,info):
return self.server.recv(info)
def show(self):
self.server.show()
class whiteInfoServerProxy(infoServerProxy):
white_list=[]
def recv(self,info):
try:
assert type(info)==dict
except:
return "info structure is not correct"
addr=info.get("addr",0)
if not addr in self.white_list:
return "Your address is not in the white list."
else:
content=info.get("content","")
return self.server.recv(content)
def addWhite(self,addr):
self.white_list.append(addr)
def rmvWhite(self,addr):
self.white_list.remove(addr)
def clearWhite(self):
self.white_list=[]
代理中有一個server字段黄琼,控制代理的服務(wù)器對象,infoServerProxy充當(dāng)Server的直接接口代理整慎,而whiteInfoServerProxy直接繼承了infoServerProxy對象脏款,同時加入了white_list和對白名單的操作。這樣裤园,在場景中使用一個白名單服務(wù)器代理類來實現(xiàn)撤师,在接收請求時,做驗證:內(nèi)容是否符合規(guī)則拧揽、訪問者的IP地址是否在白名單中剃盾,若通過則接收內(nèi)容腺占。
那么有了白名單服務(wù)器代理,該怎么使用呢痒谴?
if __name__=="__main__":
info_struct = dict()
info_struct["addr"] = 10010
info_struct["content"] = "Hello World!"
info_server = infoServer()
info_server_proxy = whiteInfoServerProxy(info_server)
print(info_server_proxy.recv(info_struct))
info_server_proxy.show()
info_server_proxy.addWhite(10010)
print (info_server_proxy.recv(info_struct))
info_server_proxy.show()
打印如下:
Your address is not in the white list.
SHOW:
recv OK!
SHOW:Hello World!
這邊我也把書中的示例放置在此衰伯。
class LazyProperty(object):
'''利用裝飾器的特性作為代理,給_resource初始化值'''
def __init__(self, method):
self.method = method
self.method_name = method.__name__
print('func name is:{}'.format(self.method_name))
def __get__(self, obj, cls):
'''使用值來替代方法'''
if not obj:
return None
value = self.method(obj)
print('value {}'.format(value))
setattr(obj, self.method_name, value)
return value
class Test(object):
def __init__(self):
self.x = 'foo'
self.y = 'bar'
self._resource = None
@LazyProperty # resource = LazyProperty(resource)
def resource(self):
print('init self._resource which is:{}'.format(self._resource))
self._resource = tuple(range(5))
return self._resource
def main():
t = Test()
print(t.x)
print(t.y)
print(t._resource)
print(t.resource)
print(t.__dict__)
print(t.resource)
# print(t._resource)
if __name__ == '__main__':
main()
該示例:使用的是裝飾器來實現(xiàn)對 resource方法的惰性加載积蔚,而該裝飾器是使用數(shù)據(jù)描述符來實現(xiàn)的意鲸,故需要對數(shù)據(jù)描述符有一定的了解。
over~~尽爆,參考:https://yq.aliyun.com/articles/70738?utm_content=m_15329怎顾,感謝。漱贱。槐雾。