代理模式
概念
- 代理就是一箇中間系統
- 代理模式關鍵在於對外屏蔽真實對象
- 通過代購可以類比一下
演員與經紀人的例子來理解一下:
class Actor(object):
def __init__(self):
self.is_busy = False
def occupied(self):
self.is_busy = True
print(type(self).__name__, '正在拍電影')
def available(self):
self.is_busy = False
print(type(self).__name__, '正在休息')
def get_status(self):
return self.is_busy
class Agent(object):
def __init__(self):
self.principal = None
def work(self):
# 給他一個演員
self.actor = Actor()
# 如果在忙就休息,如果在休息就忙起來
if self.actor.get_status():
self.actor.occupied()
else:
self.actor.available()
代理維護一個引用,代理通過這個引用訪問實際對象。代理也負責創建和刪除真實業務。
實現:
再來一個例子實現一個規模較大的代理:
付款系統
- 用戶行爲由類User表示
- 爲了購買衣服,User類提供pay方法
- 魔法方法__init__調用代理並將其實例化
- pay方法在內部調用代理的方法進行付款
- 付款成功,返回__del__方法
class User(object):
def __init__(self):
self.debit_card = DebitCard()
self.is_purchased = None
def pay(self, card_id):
self.is_purchased = self.debit_card.do_pay(card_id)
def __del__(self):
if self.is_purchased:
print('購買成功')
else:
print('購買失敗')
# 主題是付款,是一個抽象基類,
from abc import ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod
def do_pay(self):
pass
# 真實主題銀行類
class Bank(Payment):
def __init__(self):
self.card = None
self.account = None
def __get_acount(self):
self.account = self.card
return self.account
def __has_funds(self):
print('找到卡號:', self.__get_acount())
return True
def set_card(self, card):
self.card = card
def do_pay(self):
if self.__has_funds():
print('扣款成功')
return True
else:
print('扣款失敗')
return False
# 代理
class DebitCard(Payment):
def __init__(self):
self.bank = Bank()
def do_pay(self, card_id):
self.bank.set_card(card_id)
return self.bank.do_pay()
user = User()
user.pay('123456')
代理有什麼用?
- 代理可以通過緩存要頻繁訪問的對象來提高性能
- 可以比作:代購
代理和門面區別
代理模式 | 門面模式 |
---|---|
給其他對象提供了代理或者佔位符,以控制對原始對象的訪問 | 爲大型子系統提供接口 |
代理對象和目標對象接口一致,並有對目標的引用 | 實現子系統之間通信和依賴的最小化 |
充當客戶端和被封裝對象的中介 | 提供單一的簡單的接口 |
常見問題
- 裝飾器和代理區別:
- 裝飾器給正在運行時的對象添加行爲,代理是控制對象的訪問。代理不是動態的,裝飾器是動態的。
- 代理模式缺點:
- 增加響應時間,比如代理如果結構不好,就會增加時間。所以取決於代理寫的好不好
- 客戶端可以獨立訪問真實主題嗎?
- 可以,但是代理模式可以提供許多優勢:虛擬、遠程等。
- 代理能給自己添加功能嗎?
- 可以,而且無需改對象的代碼。代理和真是主題可以實現相同的接口