Python設(shè)計模式編程中的備忘錄模式與對象池模式示例
Memento備忘錄模式
備忘錄模式一個最好想象的例子:undo! 它對對象的一個狀態(tài)進行了'快照', 在你需要的時候恢復(fù)原貌。做前端會有一個場景:你設(shè)計一個表單,當(dāng)點擊提交會對表單內(nèi)容 驗證,這個時候你就要對用戶填寫的數(shù)據(jù)復(fù)制下來,當(dāng)用戶填寫的不正確或者格式不對等問題, 就可以使用快照數(shù)據(jù)恢復(fù)用戶已經(jīng)填好的,而不是讓用戶重新來一遍,不是嘛?
python的例子
這里實現(xiàn)了一個事務(wù)提交的例子
import copy def Memento(obj, deep=False): # 對你要做快照的對象做快照 state = (copy.copy if deep else copy.deepcopy)(obj.__dict__) def Restore(): obj.__dict__ = state return Restore class Transaction: deep = False def __init__(self, *targets): self.targets = targets self.Commit() # 模擬事務(wù)提交,其實就是初始化給每個對象往self.targets賦值 def Commit(self): self.states = [Memento(target, self.deep) for target in self.targets] # 回滾其實就是調(diào)用Memento函數(shù),執(zhí)行其中的閉包,將__dict__恢復(fù) def Rollback(self): for state in self.states: state() # 裝飾器的方式給方法添加這個事務(wù)的功能 def transactional(method): # 這里的self其實就是要保存的那個對象,和類的實例無關(guān) def wrappedMethod(self, *args, **kwargs): state = Memento(self) try: return method(self, *args, **kwargs) except: # 和上面的回滾一樣,異常就恢復(fù) state() raise return wrappedMethod class NumObj(object): def __init__(self, value): self.value = value def __repr__(self): return '<%s: %r>' % (self.__class__.__name__, self.value) def Increment(self): self.value += 1 @transactional def DoStuff(self): # 賦值成字符串,再自增長肯定會報錯的 self.value = '1111' self.Increment() if __name__ == '__main__': n = NumObj(-1) print n t = Transaction(n) try: for i in range(3): n.Increment() print n # 這里事務(wù)提交會保存狀態(tài)從第一次的-1到2 t.Commit() print '-- commited' for i in range(3): n.Increment() print n n.value += 'x' # will fail print n except: # 回滾只會回顧到上一次comit成功的2 而不是-1 t.Rollback() print '-- rolled back' print n print '-- now doing stuff ...' try: n.DoStuff() except: print '-> doing stuff failed!' import traceback traceback.print_exc(0) pass # 第二次的異常回滾n還是2, 整個過程都是修改NumObj的實例對象 print n
注意
當(dāng)你要保存的狀態(tài)很大,可能會浪費大量內(nèi)存
對象池模式
在開發(fā)中,我們總是用到一些和'池'相關(guān)的東西,比如 內(nèi)存池,連接池,對象池,線程池.. 這里說的對象池其實也就是一定數(shù)量已經(jīng)創(chuàng)建好的對象的集合。為什么要用對象池? 創(chuàng)建對象是要付出代價的(我暫時還沒有研究過底層,只說我工作中體會的), 比如pymongo就自帶線程池,這樣用完就放回到池里再被重用,豈不是節(jié)省了創(chuàng)建的花費?
python的例子
我這里實現(xiàn)了個線程安全的簡單的對象池
import Queue import types import threading from contextlib import contextmanager class ObjectPool(object): def __init__(self, fn_cls, *args, **kwargs): super(ObjectPool, self).__init__() self.fn_cls = fn_cls self._myinit(*args, **kwargs) def _myinit(self, *args, **kwargs): self.args = args self.maxSize = int(kwargs.get("maxSize",1)) self.queue = Queue.Queue() def _get_obj(self): # 因為傳進來的可能是函數(shù),還可能是類 if type(self.fn_cls) == types.FunctionType: return self.fn_cls(self.args) # 判斷是經(jīng)典或者新類 elif type(self.fn_cls) == types.ClassType or type(self.fn_cls) == types.TypeType: return apply(self.fn_cls, self.args) else: raise "Wrong type" def borrow_obj(self): # 這個print 沒用,只是在你執(zhí)行的時候告訴你目前的隊列數(shù),讓你發(fā)現(xiàn)對象池的作用 print self.queue._qsize() # 要是對象池大小還沒有超過設(shè)置的最大數(shù),可以繼續(xù)放進去新對象 if self.queue.qsize()<self.maxSize and self.queue.empty(): self.queue.put(self._get_obj()) # 都會返回一個對象給相關(guān)去用 return self.queue.get() # 回收 def recover_obj(self,obj): self.queue.put(obj) # 測試用函數(shù)和類 def echo_func(num): return num class echo_cls(object): pass # 不用構(gòu)造含有__enter__, __exit__的類就可以使用with,當(dāng)然你可以直接把代碼放到函數(shù)去用 @contextmanager def poolobj(pool): obj = pool.borrow_obj() try: yield obj except Exception, e: yield None finally: pool.recover_obj(obj) obj = ObjectPool(echo_func, 23, maxSize=4) obj2 = ObjectPool(echo_cls, maxSize=4) class MyThread(threading.Thread): def run(self): # 為了實現(xiàn)效果,我搞了個簡單的多線程,2個with放在一個地方了,只為測試用 with poolobj(obj) as t: print t with poolobj(obj2) as t: print t if __name__ == '__main__': threads = [] for i in range(200): t = MyThread() t.start() threads.append(t) for t in threads: t.join(True)
欄 目:C#教程
下一篇:C#提取網(wǎng)頁中超鏈接link和text部分的方法
本文標(biāo)題:Python設(shè)計模式編程中的備忘錄模式與對象池模式示例
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/6724.html
您可能感興趣的文章
- 01-10C#編程實現(xiàn)自定義熱鍵的方法
- 01-10C#編程獲取資源文件中圖片的方法
- 01-10深入淺出23種設(shè)計模式
- 01-10C#編程自學(xué)之?dāng)?shù)據(jù)類型和變量二
- 01-10C#編程自學(xué)之開篇介紹
- 01-10C#編程自學(xué)之?dāng)?shù)據(jù)類型和變量三
- 01-10C#編程自學(xué)之運算符和表達式
- 01-10C#編程自學(xué)之類和對象
- 01-10C#編程和Visual Studio使用技巧(下)
- 01-10C#編程自學(xué)之?dāng)?shù)據(jù)類型和變量一


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實現(xiàn)txt定位指定行完整實例
- 01-10WinForm實現(xiàn)仿視頻 器左下角滾動新
- 01-10C#停止線程的方法
- 01-10C#實現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實現(xiàn)讀取注冊表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機閱讀
- 01-10delphi制作wav文件的方法
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-11ajax實現(xiàn)頁面的局部加載
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10C#中split用法實例總結(jié)
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 04-02jquery與jsp,用jquery