美文网首页
备忘录模式(Memento Pattern)

备忘录模式(Memento Pattern)

作者: long弟弟 | 来源:发表于2022-09-18 11:59 被阅读0次

    备忘录模式,快照模式(Snapshot Pattern)

    意图:在不违背封装的前提下,捕获一个对象的内部状态,并在该状态之外保持这个状态,以便之后恢复对象为先前的状态。

    备忘录模式的作用就是保存对象的内部状态,并在需要的时候(undo/rollback)恢复对象以前的状态。

    备忘录模式.jpg

    角色和职责

    1. Originator(原生者,原发器)
      需要被保存状态以便恢复的那个对象
      创建一个备忘录,用以记录当前时刻它的内部状态
      使用备忘录恢复内部状态
    2. Memento(备忘录)
      该对象由Originator创建,主要用来保存Originator的内部状态
      根据需要决定备忘录存储原生者的哪些内部状态
      防止原生者以外的其他对象访问备忘录
      备忘录实际上有两个接口,管理者只能看到备忘录的窄接口(它只能将备忘录传递给其他对象);原生者能看到一个宽接口,允许它访问返回到先前状态所需的所有数据
    3. Caretaker(管理者)
      负责保存好备忘录
      不能对备忘录的内容进行操作或检查

    代码示例

    原生者和备忘录

    #import <Foundation/Foundation.h>
    @interface Memento : NSObject
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, assign) NSInteger age;
    @end
    @implementation Memento
    - (instancetype)initWithName:(NSString *)name AndAge:(NSInteger)age {
        if (self = [super init]) {
            self.name = name;
            self.age = age;
        }
        return self;
    }
    @end
    
    @interface Person : NSObject
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, assign) NSInteger age;
    @end
    @implementation Person
    - (instancetype)initWithName:(NSString *)name AndAge:(NSInteger)age {
        if (self = [super init]) {
            self.name = name;
            self.age = age;
        }
        return self;
    }
    //保存到备忘录
    - (Memento *)saveMemento {
        return [[Memento alloc] initWithName:self.name AndAge:self.age];
    }
    //从备忘录恢复
    - (void)restoreMemento:(Memento *)memento {
        self.name = memento.name;
        self.age = memento.age;
    }
    - (NSString *)description {
        return [NSString stringWithFormat:@"%@ %ld岁", self.name, self.age];
    }
    @end
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            Person *p1 = [[Person alloc] initWithName:@"张三" AndAge:18];
            NSLog(@"创建之后:%@", p1);
            Memento *memento = [p1 saveMemento];
            p1.age = 19;
            NSLog(@"修改之后:%@", p1);
            [p1 restoreMemento:memento];
            NSLog(@"从备忘录中恢复:%@", p1);
        }
        return 0;
    }
    /*
    创建之后:张三 18岁
    修改之后:张三 19岁
    从备忘录中恢复:张三 18岁
    */
    

    原生者、备忘录和备忘录管理者

    #import <Foundation/Foundation.h>
    @interface Memento : NSObject
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, assign) NSInteger age;
    @end
    @implementation Memento
    - (instancetype)initWithName:(NSString *)name AndAge:(NSInteger)age {
        if (self = [super init]) {
            self.name = name;
            self.age = age;
        }
        return self;
    }
    @end
    //备忘录管理者
    @interface Caretaker : NSObject
    @property (nonatomic, strong) Memento *memento;
    @end
    @implementation Caretaker
    - (instancetype)initWithMemento:(Memento *)memento {
        if (self = [super init]) {
            self.memento = memento;
        }
        return self;
    }
    @end
    
    @interface Person : NSObject
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, assign) NSInteger age;
    @end
    @implementation Person
    - (instancetype)initWithName:(NSString *)name AndAge:(NSInteger)age {
        if (self = [super init]) {
            self.name = name;
            self.age = age;
        }
        return self;
    }
    //保存到备忘录
    - (Memento *)saveMemento {
        return [[Memento alloc] initWithName:self.name AndAge:self.age];
    }
    //从备忘录恢复
    - (void)restoreMemento:(Memento *)memento {
        self.name = memento.name;
        self.age = memento.age;
    }
    - (NSString *)description {
        return [NSString stringWithFormat:@"%@ %ld岁", self.name, self.age];
    }
    @end
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            Person *p1 = [[Person alloc] initWithName:@"张三" AndAge:18];
            NSLog(@"创建之后:%@", p1);
            Caretaker *caretaker = [[Caretaker alloc] initWithMemento:[p1 saveMemento]];
            p1.age = 19;
            NSLog(@"修改之后:%@", p1);
            [p1 restoreMemento:caretaker.memento];
            NSLog(@"从备忘录中恢复:%@", p1);
        }
        return 0;
    }
    /*
    创建之后:张三 18岁
    修改之后:张三 19岁
    从备忘录中恢复:张三 18岁
    */
    

    用处

    如果一个对象需要保存状态并可通过undo或rollback等操作恢复到以前的状态时,可以使用备忘录模式。

    1. 一个类需要保存它的对象的状态(相当于Originator角色)
    2. 设计一个类,该类知识用来保存上述对象的状态(相当于Memento角色)
    3. 需要的时候,Caretaker角色要求Originator返回一个Memento并加以保存
    4. undo或rollback操作时,通过Caretaker保存的Memento恢复Originator对象的状态

    适用于功能比较复杂的,但需要记录或维护属性历史的类;或者需要保存的属性只是众多属性中的一小部分时Originator可以根据保存的Memo还原到前一状态。

    iOS中的序列化和反序列化可以理解为备忘录模式的经典应用,用以防丢失、撤销、恢复。iOS系统提供的的类有的如NSArrayNSDictionary等已经实现了NSCoding协议
    自定义的类实现备忘录模式

    1. 遵守NSCoding协议
    2. 实现协议中的方法- (void)encodeWithCoder:(NSCoder *)coder;- (nullable instancetype)initWithCoder:(NSCoder *)coder;

    写到这里是不是体会到了,备忘录模式就是存储方案,保存状态、恢复状态...

    优点

    1. 保持封装边界
      使用备忘录可以避免暴漏一些只应由原发者管理却又必须存储在原发者之外的信息。该模式把可能很复杂的Originator内部信息对其他对象屏蔽起来,从而保持了封装边界。
    2. 简化了原发者
      在其他的保持封装性的设计中,Originator负责保持客户请求过的内部状态版本。这就把所有存储管理的重任交给了Originator。让客户管理它们请求的状态将会简化Originator,并且使得客户工作结束时无需通知原发者。

    缺点

    1. 使用备忘录的代价可能很高
      如果原发者在生成备忘录时必须拷贝并存储大量的信息,或客户非常频繁的创建备忘录和恢复原发者状态,可能会导致非常大的开销。
    2. 维护备忘录的潜在代价
      管理者负责删除它所维护的备忘录。然而,管理者并不知道备忘录中有多少个状态。因此当存储备忘录时,一个本来很小的管理者,可能会产生大量的存储开销。

    相关文章

      网友评论

          本文标题:备忘录模式(Memento Pattern)

          本文链接:https://www.haomeiwen.com/subject/dxhegrtx.html