设计模式-备忘录模式-memento-python??

来源:互联网 发布:淘宝官微 编辑:程序博客网 时间:2024/05/29 16:42

def

在不破坏封装性的前提下, 捕获一个对象的内部状态, 并在该对象之外保存这个状态。 这样以后就可将该对象恢复到原先保存的状态。

usage

● 需要保存和恢复数据的相关状态场景。
● 提供一个可回滚(rollback) 的操作; 比如Word中的CTRL+Z组合键, IE浏览器中的后退按钮, 文件管理器上的backspace键等。
● 需要监控的副本场景中。 例如要监控一个对象的属性, 但是监控又不应该作为系统的主业务来调用, 它只是边缘应用, 即使出现监控不准、 错误报警也影响不大, 因此一般的做法是备份一个主线程中的对象, 然后由分析程序来分析。
● 数据库连接的事务管理就是用的备忘录模式, 想想看, 如果你要实现一个JDBC驱动, 你怎么来实现事务? 还不是用备忘录模式嘛

code

from copy import copyfrom copy import deepcopydef memento(obj, deep=False):    state = deepcopy(obj.__dict__) if deep else copy(obj.__dict__)    def restore():        obj.__dict__.clear()        obj.__dict__.update(state)    return restoreclass Transaction(object):    """A transaction guard.    This is, in fact, just syntactic sugar 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):    """Adds transactional semantics to methods. Methods decorated  with    @Transactional will rollback to entry-state upon exceptions.    """    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 transactionclass 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'  # <- invalid value        self.increment()  # <- will fail and rollbackif __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'  # will fail        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)### OUTPUT #### <NumObj: -1># <NumObj: 0># <NumObj: 1># <NumObj: 2># -- committed# <NumObj: 3># <NumObj: 4># <NumObj: 5># -- rolled back# <NumObj: 2># -- now doing stuff ...# -> doing stuff failed!# Traceback (most recent call last):# File "memento.py", line 97, in <module>#     num_obj.do_stuff()#   File "memento.py", line 52, in transaction#     raise e#   File "memento.py", line 49, in transaction#     return self.method(obj, *args, **kwargs)#   File "memento.py", line 70, in do_stuff#     self.increment()     # <- will fail and rollback#   File "memento.py", line 65, in increment#     self.value += 1# TypeError: Can't convert 'int' object to str implicitly# <NumObj: 2>