1. 程式人生 > >用例項理解設計模式——代理模式(Python版)

用例項理解設計模式——代理模式(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

代理模式:為其他物件提供一種代理以控制對這個物件的訪問。 在某些情況下,一個物件不適合或者不能直接引用另一個物件,而代理物件可以在客戶端和目標物件之間起到中介的作用。 代理模式分為: 靜態代理 動態代理 由下面三部分組成: 抽象角色:通過介面或抽象類宣告真實角色實現的業務方法。 代理角色:實現抽象角色

二十一狀態模式詳解DOTA

作者:zuoxiaolong8810(左瀟龍),轉載請註明出處,特別說明:本博文來自博主原部落格,為保證新部落格中博文的完整性,特複製到此留存,如需轉載請註明新部落格地址即可。                本次LZ

簡單工廠模式python

什麼是簡單工廠模式 工廠模式有一種非常形象的描述,建立物件的類就如一個工廠,而需要被建立的物件就是一個個產品;在工廠中加工產品,使用產品的人,不用在乎產品是如何生產出來的。從軟體開發的角度來說,這樣就有效的降低了模組之間的耦合。 簡單工廠的作用是例項化物件,而不需要客戶瞭解這個物件屬於哪個

裝飾模式python

目錄 什麼是裝飾模式 裝飾模式(Decorator),動態的給一個物件新增一些格外的職責,就增加功能來說,裝飾模式比生成子類更靈活 裝飾模式UML圖 Component是定義一個物件介面,可以給這些物件動態的新增職責。C

RDIFramework.NET -.NET快速資訊化系統開發整合框架 【開發例項 EasyUI】之產品管理WebForm

RDIFramework.NET—.NET快速開發整合框架 【開發例項】之產品管理(WebForm版) 第1部分 概述    RDIFramework.NET,基於.NET的快速資訊化系統開發、整合框架,為企業或個人在.NET環境下快速開發系統提供了強大的支援,開發人 員不需要開發系統的基礎功能和公

RDIFramework.NET-.NET快速資訊化系統開發整合框架 【開發例項 EasyUI】之產品管理MVC

RDIFramework.NET—.NET快速開發整合框架 【開發例項】之產品管理(MVC版) 第1部分 概述   RDIFramework.NET,基於.NET的快速資訊化系統開發、整合框架,為企業或個人在.NET環境下快速開發系統提供了強大的支援,開發人員不需要開發系統的基礎功能和公共模組,框架

RDIFramework.NET—.NET快速開發整合框架 【開發例項 EasyUI】之產品管理WebForm

RDIFramework.NET—.NET快速開發整合框架【開發例項】之產品管理(WebForm版)第1部分 概述   RDIFramework.NET,基於.NET的快速資訊化系統開發、整合框架,為企業或個人在.NET環境下快速開發系統提供了強大的支援,開發人 員不需要開發

socket穿透代理程式碼C++

寫程式碼經常會遇到socket要通過代理連線伺服器的情況,代理型別通暢有三種:HTTP、SOCK4和SOCK5,通過學習和網上參考相關程式碼,寫了個代理類來實現該功能,貼出來與大家共享 http://blog.csdn.net/bodybo/article/detail

劍指Offer-- 翻轉鏈表 python

head 鏈表 pytho blog write ini pre 當前 返回 輸入一個鏈表,反轉鏈表後,輸出鏈表的所有元素。 # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, x): #

編碼的秘密python

默認 字節數 二進制格式 type eight 符號 占用 終端 自己 編碼(python版) 最近在學習python的過程中,被不同的編碼搞得有點暈,於是看了前人的留下的文檔,加上自己的理解,準備寫下來,分享給正在為編碼苦苦了掙紮的你。 編碼的概念 編碼就是將信息從一

代碼這樣寫更優雅Python (轉載)

python 初學 return 閱讀 沒有 邏輯 刪除元素 python3 list ask   轉載:https://mp.weixin.qq.com/s?timestamp=1498528588&src=3&ver=1&signature=Df

【Spark MLlib速成寶典】模型篇04樸素貝葉斯【Naive Bayes】Python

width pla evaluate 特征 mem order 一個數 ble same 目錄   樸素貝葉斯原理   樸素貝葉斯代碼(Spark Python) 樸素貝葉斯原理   詳見博文:http://www.cnblogs.com/itmor

【Spark MLlib速成寶典】模型篇05決策樹【Decision Tree】Python

back filter oms sse mlu eval ffffff size red 目錄   決策樹原理   決策樹代碼(Spark Python) 決策樹原理   詳見博文:http://www.cnblogs.com/itmorn/p/79

四則運算生成程序python

本地化 tee 情況 class 數字 是否 波蘭表達式 api 提示 四則運算題目生成—基於控制臺 項目托管在碼雲:飛機票 需求分析 根據控制臺提示信息,輸入題目生成相關配置參數 題目生成數量 數字範圍 式子中是否有分數 .... 程序支持 10000 題目生成

線性表應用--Josephus問題的解法Python

pytho 人的 clas 基於 列表 設有 return 所有 下一個 線性表應用 --Josephus問題的解法(Python 版) Josephus問題描述:假設有n個人圍坐一圈,現在要求從第k個人開始報數,報到第m個數的人退出。然後從下一個人開

棧應用之 括號匹配問題Python

text 所有 != parent else 括號 check style pan 棧應用之 括號匹配問題(Python 版) 檢查括號是否閉合 循序掃描被檢查正文(一個字符)裏的一個個字符 檢查中跳過無關字符(所有非括號字符都與當前處理無關) 遇到開括號將其壓入棧 遇到

編程導論Python

面向對象 軟件 創建 算法 圖形界面 進程 數據結構與算法 隨機 機器學習 第1篇 計算機科學基礎 一、計算機組成原理 二、計算機網絡原理 三、操作系統原理 四、編譯原理 五、軟件工程原理 第2篇 Python程序設計基礎

拓撲排序|Topological Sort類演算法題心得PYTHON

拓撲排序 尋找專案之間依賴順序的過程稱為拓撲排序(topological sorting)。   首先要了解有向無環圖|Directed Acyclic Graph: 用字典表示:G = { 'a':'bce', 'b':'d','c':'d','d':'','e':'cd'} Key

protobuf安裝使用python

安裝 protobuf原始碼(各種語言實現) https://github.com/google/protobuf  我們只需要python版和protoc(編譯proto到各個語言) 1、到Python目錄,編譯  python setup.py build&

批量圖片重新命名python

參考:https://blog.csdn.net/m0_37592397/article/details/80372009 # -*- coding:utf8 -*- import os class BatchRename(): """ 批量重新命名資料夾