Python設計模式之代理模式

代理模式

概念

  • 代理就是一箇中間系統
  • 代理模式關鍵在於對外屏蔽真實對象
  • 通過代購可以類比一下

演員與經紀人的例子來理解一下:

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')

代理有什麼用?

  • 代理可以通過緩存要頻繁訪問的對象來提高性能
  • 可以比作:代購

代理和門面區別

代理模式 門面模式
給其他對象提供了代理或者佔位符,以控制對原始對象的訪問 爲大型子系統提供接口
代理對象和目標對象接口一致,並有對目標的引用 實現子系統之間通信和依賴的最小化
充當客戶端和被封裝對象的中介 提供單一的簡單的接口

常見問題

  • 裝飾器和代理區別:
    • 裝飾器給正在運行時的對象添加行爲,代理是控制對象的訪問。代理不是動態的,裝飾器是動態的。
  • 代理模式缺點:
    • 增加響應時間,比如代理如果結構不好,就會增加時間。所以取決於代理寫的好不好
  • 客戶端可以獨立訪問真實主題嗎?
    • 可以,但是代理模式可以提供許多優勢:虛擬、遠程等。
  • 代理能給自己添加功能嗎?
    • 可以,而且無需改對象的代碼。代理和真是主題可以實現相同的接口
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章