"""
備忘錄模式:在不破壞封裝性的前提下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài)。
這樣以后就可將該對象恢復到原先保存的狀態(tài)。
跟原型模式很像,不過在原型模式中保存對象的一切,而備忘錄模式中只保存恢復時需要的數(shù)據(jù)。
"""
from?copy?import?copy,?deepcopy
def?memento(obj,?deep=False):
????state?=?deepcopy(obj.__dict__)?if?deep?else?copy(obj.__dict__)
????def?restore():
????????obj.__dict__.clear()
????????obj.__dict__.update(state)
????return?restore
class?Transaction:
????"""
????一個事務守護.
??????這一點,事實上,?就是語法糖?around?a?memento?closure.
????"""
????deep?=?False
????states?=?[]
????def?__init__(self,?deep,?*targets):
????????self.deep?=?deep
????????self.targets?=?targets
????????self.commit()
????def?commit(self):
????????self.states?=?[memento(target,?self.deep)?for?target?in?self.targets]
????def?rollback(self):
????????for?a_state?in?self.states:
????????????a_state()
class?Transactional(object):
????"""
????添加事務語義方法。方法用@Transactional裝飾,在異常時將回滾到進入狀態(tài)。
????"""
????def?__init__(self,?method):
????????self.method?=?method
????def?__get__(self,?obj,?T):
????????def?transaction(*args,?**kwargs):
????????????state?=?memento(obj)
????????????try:
????????????????return?self.method(obj,?*args,?**kwargs)
????????????except?Exception?as?e:
????????????????state()
????????????????raise?e
????????return?transaction
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?do_stuff(self):
????????self.value?=?'1111'??#?<-?無效的值
????????self.increment()??#?<-?將失敗并回滾
if?__name__?==?'__main__':
????num_obj?=?NumObj(-1)
????print(num_obj)
????a_transaction?=?Transaction(True,?num_obj)
????try:
????????for?i?in?range(3):
????????????num_obj.increment()
????????????print(num_obj)
????????a_transaction.commit()
????????print('--?committed')
????????for?i?in?range(3):
????????????num_obj.increment()
????????????print(num_obj)
????????num_obj.value?+=?'x'??#?將失敗
????????print(num_obj)
????except?Exception?as?e:
????????a_transaction.rollback()
????????print('--?rolled?back')
????print(num_obj)
????print('--?now?doing?stuff?...')
????try:
????????num_obj.do_stuff()
????except?Exception?as?e:
????????print('->?doing?stuff?failed!')
????????import?sys
????????import?traceback
????????traceback.print_exc(file=sys.stdout)
????print(num_obj)