1. 程式人生 > >淺談Python設計模式 - 代理模式

淺談Python設計模式 - 代理模式

 

  宣告:本系列文章主要參考《精通Python設計模式》一書,並且參考一些資料,結合自己的一些看法來總結而來。

  一、在某些應用中,我們想要在訪問某個物件之前執行一個或者多個重要的操作,例如,訪問敏感資訊 -- 在允許使用者訪問敏感資訊之前,我們希望確保使用者具備足夠的去許可權。同時在網路訪問時,限制某些網路的訪問等操作。

  二、把一個計算成本較高的物件的建立過程延遲到使用者首次真正使用它的時候才進行。

  以上的情況就可以使用 代理設計模式 

  代理模式:因使用代理物件再訪問實際物件之前執行重要操作而得其名。

  示例:

  之前想用《精通Python設計模式》中的示例來說明,但是發現很負責不太好理解,於是有了接下來的示例:

阿里雲:Python與設計模式 -代理模式

  一、首先構件一個網路伺服器:

#該伺服器接受如下格式資料,addr代表地址,content代表接收的資訊內容
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有接收和傳送的功能,傳送功能由於暫時用不到,保留。另外新加一個介面show,用來展示伺服器接收的內容。接收的資料格式必須如info_struct所示,伺服器僅接受info_struct的content欄位。

 

  二、若此時有需求,該網路伺服器只允許部分網路IP進行訪問,那麼需要設定白名單,該怎麼做呢?顯然可以有如下兩種方式:

  ①、修改Server結構是個方法,即在進入server時,做一系列邏輯判斷。但這顯然不符合軟體設計原則中的單一職責原則

  ②、使用代理,即利用代理來進行邏輯判定,若在白名單中,則允許訪問,若不在則拒絕。

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欄位,控制代理的伺服器物件,infoServerProxy充當Server的直接介面代理,而whiteInfoServerProxy直接繼承了infoServerProxy物件,同時加入了white_list和對白名單的操作。這樣,在場景中使用一個白名單伺服器代理類來實現,在接收請求時,做驗證:內容是否符合規則、訪問者的IP地址是否在白名單中,若通過則接收內容。

   那麼有了白名單伺服器代理,該怎麼使用呢?

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()
精通Python設計模式--示例

 該示例:使用的是裝飾器來實現對 resource方法的惰性載入,而該裝飾器是使用資料描述符來實現的,故需要對資料描述符有一定的瞭解。

 

  over~~,參考:https://yq.aliyun.com/articles/70738?utm_content=m_15329,感謝。。。