<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
設計模式中經常提到的代理模式、裝飾模式,這兩種叫法實際上是說的同一件事,只是側重點有所不同而已。
這兩者都是通過在原有物件的基礎上封裝一層物件,通過呼叫封裝後的物件而不是原來的物件來實現代理/裝飾的目的。
例如:(以Java為例)
public class CountProxy implements Count { private CountImpl countImpl; public CountProxy(CountImpl countImpl) { this.countImpl = countImpl; } @Override public void queryCount() { System.out.println("事務處理之前"); // 呼叫委託類的方法; countImpl.queryCount(); System.out.println("事務處理之後"); } @Override public void updateCount() { System.out.println("事務處理之前"); // 呼叫委託類的方法; countImpl.updateCount(); System.out.println("事務處理之後"); } }
在這個例子中CountProxy
是對CountImpl
的封裝。
使用者通過CountProxy.queryCount
方法來呼叫CountImpl.queryCount
方法,這被稱為代理,即CountProxy
是代理類,CountImpl
是被代理類。
在CountProxy.queryCount
方法中,可以在CountImpl.queryCount
方法呼叫之前和之後新增一些額外的操作,被稱為裝飾,即CountProxy
是裝飾類,CountImpl
是被裝飾類。
如果強調通過CountProxy
對CountImpl
進行代理的作用,則稱為代理模式;
如果強調通過CountProxy
對CountImpl
增加額外的操作,則稱為裝飾模式;
不論是哪種稱呼,其本質都在於對原有物件的封裝。
其封裝的目的在於增強所封裝物件的功能或管理所封裝的物件。
從上面的例子也可以發現,代理/封裝所圍繞的核心是可呼叫物件(比如函數)。
Python中的可呼叫物件包括函數、方法、實現了__call__方法的類。
Python中的函數也是物件,可以作為高階函數的引數傳入或返回值返回。
因此,當代理/裝飾的物件是函數時,可以使用高階函數來對某個函數進行封裝。
例如:
def query_count_proxy(fun, name, age): print('do something before') rv = fun(name, age) print('do something after') return rv def query_count(name, age): print('name is %s, age is %d' % (name, age)) query_count_proxy(query_count, 'Lee', 20)
但是,這個例子中,query_count
函數作為引數傳入query_count_proxy
函數中,並在query_count_proxy
函數中被呼叫,其結果作為返回值返回。這就完成了代理的功能,同時,在呼叫query_count
函數的前後,我們還增加了裝飾程式碼。
但是,query_count_proxy
的函數引數與query_count
不一樣了,理想的代理應該保持介面一致才對。
為了保持一致,我們可以利用高階函數可以返回函數的特點來完成:
def query_count_proxy(fun): def wrapper(name, age): print('do something before') rv = fun(name, age) print('do something after') return rv return wrapper def query_count(name, age): print('name is %s, age is %d' % (name, age)) query_count_proxy(query_count)('Lee', 20)
修改後的例子,query_count_proxy
僅負責接受被代理的函數query_count
作為引數,同時,返回一個函數物件wrapper
作為返回值,真正的封裝動作在wrapper
這個函數中完成。
此時,如果呼叫query_count_proxy(query_count)
就得到了wrapper
函數物件,則,執行query_count_proxy(query_count)('Lee', 20)
就相當於執行了wrapper('Lee', 20)
。
但是可以看到,query_count_proxy(query_count)('Lee', 20)
這種使用方法,仍然不能保證一致。
為了保持一致,我們需要利用Python中物件與其名稱可以動態繫結的特點。不使用query_count_proxy(quer_count)('Lee', 20)
來呼叫代理函數,而是使用下面兩句:
query_count = query_count_proxy(query_count) query_count('Lee', 20)
執行query_count_proxy(query_count)
生成wrapper
函數物件,將這個物件通過query_count = query_count_proxy(query_count)
繫結到query_count
這個名字上來,這樣執行query_count('Lee', 20)
時,其實執行的是wrapper('Lee', 20)
。
這麼做的結果就是:使用代理時呼叫query_count('Lee', 20)
與不使用代理時呼叫query_count('Lee', 20)
對使用者而言保持不變,不用改變程式碼,但是在真正執行時,使用的是代理/裝飾後的函數。
這裡,基本利用Python的高階函數及名稱繫結完成了代理/裝飾的功能。
對,就是query_count = query_count_proxy(query_count)
,因為這句既不簡潔,又屬於重複工作。
Python為我們提供了語法糖來完成這類的tedious work。
方法就是:
@query_count_proxy def query_count(name, age): return 'name is %s, age is %d' % (name, age)
query_count = query_count_proxy(query_count)
就等同於在定義query_count
函數的時候,在其前面加上@query_count_proxy
。
Python看到這樣的語法,就會自動的執行query_count = query_count_proxy(query_count)
進行name rebinding
以上就是Python實現可呼叫物件裝飾的核心。
可呼叫物件包括函數、方法、實現了__call__方法的類,上述內容只是針對函數來解釋,對於方法、實現了__call__方法的類,其基本原理相同,具體實現略有差別。
以上就是Python Decorator的設計模式演繹過程解析的詳細內容,更多關於Python Decorator設計模式的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45