設計模式-結構型模式,代理模式(9)


在某些應用中,我們想要在訪問某個對象之前執行一個或多個重要的操作,例如,訪問敏感
信息——在允許用戶訪問敏感信息之前,我們希望確保用戶具備足夠的權限。操作系統中也存在
類似的情況,用戶必須具有管理員權限才能在系統中安裝新程序。
上面提到的重要操作不一定與安全問題相關。延遲初始化
是另一個案例:我們想要把一個計算成本較高的對象的創建過程延遲到用戶首次真正使用它時
才進行。

 

在代理模式(Proxy Pattern)中,一個類代表另一個類的功能。這種類型的設計模式屬於結構型模式。

在代理模式中,我們創建具有現有對象的對象,以便向外界提供功能接口。

 

# coding: utf-8


class SensitiveInfo:

    def __init__(self):
        self.users = ['nick', 'tom', 'ben', 'mike']

    def read(self):
        print('There are {} users: {}'.format(len(self.users), ' '.join(self.users)))

    def add(self, user):
        self.users.append(user)
        print('Added user {}'.format(user))


class Info:

    '''SensitiveInfo的保護代理'''

    def __init__(self):
        self.protected = SensitiveInfo()
        self.secret = '0xdeadbeef'

    def read(self):
        self.protected.read()

    def add(self, user):
        sec = input('what is the secret? ')
        self.protected.add(user) if sec == self.secret else print("That's wrong!")


def main():
    info = Info()
    while True:
        print('1. read list |==| 2. add user |==| 3. quit')
        key = input('choose option: ')
        if key == '1':
            info.read()
        elif key == '2':
            name = input('choose username: ')
            info.add(name)
        elif key == '3':
            exit()
        else:
            print('unknown option: {}'.format(key))

if __name__ == '__main__':
    main()

 

代理模式是非常重要常見的一種模式,通過組合一個現有類來改變一些方法。如下,可以通過其他方式定位元素,還能改變元素的輸入 點擊行為,難點的怎么點擊元素都在現有類的方法中實現了,寫代理類的方法很簡單。

#encoding=utf-8
import time
from selenium import webdriver
from selenium.webdriver.remote.webelement import WebElement


class Browser(object):

    def __init__(self,class_):
        if class_ == webdriver.Chrome:
            self.driver = webdriver.Chrome()


    def find_element_through_id(self,id):
        self.driver.find_element_by_id(id)
        print '通過 ' + id + ' 查找這個元素'




class Element():
    def __init__(self,ele):
        """
        :type ele:WebElement
        """
        self.ele = ele

    def click(self):
        self.ele.click()
        time.sleep(2)

    def input(self,value):
        self.ele.send_keys(value)
        print '填了一個值: ' + value
        time.sleep(3)


browser = Browser(webdriver.Chrome)
Element(browser.find_element_through_id('shurukuang_id')).input('hello world')
Element(browser.find_element_through_id('button_id')).click()

 

 

以上模式,叫代理模式。

2、認真看下,就不難發現,這貨其實也可以用繼承來解決。?

 

總結下區別就是:

代理在A類中  self.b = B()。self.b.fun() A類的實例通過操作成員變量b來執行方法

繼承是 class  A(B)。 self.fun(),A繼承B的所有方法

那為啥要代理不要繼承?我覺得在靈活性上代理要比繼承好,例如上面的selnium例子,Broser可以組合火狐 谷歌 ie多種瀏覽器,如果繼承那就要多種繼承了。組合一個什么對象是動態的,繼承一個什么類那是固定的是的。

代理模式的類比較干凈,不會一股腦復制父類的方法,在智能ide自動補全上好很多,不會一股腦補全父類中在本類中不需用的方法,通過操作成員變量來操作一些方法。

 

知乎的答案就是我要說的意思。

繼承和代理都是代碼復用的方式。

繼承是把要復用的代碼(即父對象)的所有屬性和行為都復用。不管用得着用不着,先一鼓腦都繼承過來。

代理是把要復用的對象作為自己的成員變量,然后在自己的方法中通過這個成員變量去調用要復用的對象的方法。這樣就獲得了要復用的對象的部分功能,而不用把要復用的對象的全部屬性和方法都復用過來。可以稱為部分繼承或者方法借用模式。相比繼承來說,更靈活。



設計模式就是一堆組合和繼承的變幻而來。
 
3、除了使用組合對象來實現代理模式和繼承來實現代理模式的作用,python是動態語言,屬性在運行時確定。
比如不喜歡selneium Chrome類原生的find_element_by_cssselector()方法,想自己叫個簡短的方法名,或者修改里面的方法。也可以使用猴子補丁。代碼如下
 
 
# coding=utf-8
import time
from selenium.webdriver import Chrome as ChromePatcher
from selenium.webdriver.remote.webelement import WebElement

def by_css(browser, *args):
    print 'hi'  ##舉個例子,代表修改原生方法
    return ChromePatcher.find_element_by_css_selector(browser, *args)

ChromePatcher.by_css = by_css      ###賦值,如果函數名與原類同名叫替換方法,不同名叫增加方法。

browser = ChromePatcher()
browser.get('https://www.baidu.com')
browser.by_css('#kw').send_keys(u'美女')

 

      
通過這樣就可以修改原類的方法實現或方法名修改。
這種沒有用到類對象組合和繼承,而是在模塊中定義一個方法,然后將原類的方法替換為自己定義的方法,或者增加一個方法。
類外定義方法的時候要記住,第一個參數是代表對象本身,這個不要省略了,否則參數解析出錯。第一個參數一般叫self ,也可以叫browser或者任何名稱都可以。
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM