前言
备忘录定义为"作为某人或某事的提醒物或纪念品而保留下来的物品"。每当我们需要记下一个事情时,就会把它写到某个地方。存放的时间长短由信息本身决定,当信息失效以后,我们就会丢弃它。
在面向对象的设计模式中,借用类似的思想,来保存对象的状态并在后来进行恢复。状态本身被创建为一种对象形式。它封装了原始对象的内部状态。从这一思想设计而来的一种设计模式叫做备忘录模式。
什么是备忘录模式
备忘录模式在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。在响应某些事件时,应用程序需要保存自身的状态。
这个模式有三个角色:原发器(origninator)、备忘录(Menmento) 和看管人(Caretaker)。其思想非常简单。原发器创建一个包含其状态的备忘录,并传给看管人。看管人负责把备忘录放在安全之处保管好。当看管人请求 Origninator
对象保存其状态时,Origninator
对象将使用其内部状态创建一个新的 Memento
实例。然后看管人保管 Meomento
对象。在这个过程中,Originator
对象不知道这个 Memento
对象如何被保存。看管人也不知道 Memento
对象是什么。
什么时候使用备忘录模式
- 需要保存/恢复数据的相关状态场景。
- 提供一个可回滚的操作。
备忘录模式的优缺点
备忘录模式的优点
- 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。
- 实现了信息的封装,使得用户不需要关心状态的保存细节。
备忘录模式的缺点
消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。
Cocoa 中的备忘录
Archiver
归档将程序中的对象与这些对象的属性(属性和关系)一起转换为可以存储在文件系统中或在进程之间或通过网络传输的存档。档案记录了程序的对象图作为独立于体系结构的字节流,保留对象的身份和它们之间的关系。因为对象的类型与其数据一起存储,所以从字节流解码的对象通常使用与最初编码的对象相同的类来实例化。被编码和解码的对象必须符合NSCoding
协议,该协议的方法在归档期间被调用。
Property List 序列化
Property List 是对象图的简单结构化序列化,它仅使用以下类的对象:NSDictionary
、NSArray
、NSString
、NSData
、NSDate
和NSNumber
。这些对象通常称为 property list objects。Cocoa 框架类提供了一些序列化这些属性列表对象的方法,并为记录对象内容及其层次关系的数据流定义了特殊格式。NSPropertyListSerialization
类提供了将 property list 对象序列化为 XML 格式或优化的二进制格式的类方法。
Core Data
Core Data 是一个 Cocoa 框架,它定义了用于管理对象图并使它们持久化的架构。在 Core Data 架构中,一个中心对象称为托管对象上下文管理应用程序中的各种模型对象对象图。托管对象上下文下方是该对象图的持久性堆栈——在模型对象和外部数据存储(例如 XML 文件或关系数据库)之间进行中介的框架对象的集合。持久性堆栈对象在存储中的数据和托管数据上下文中的相应对象之间进行映射,并且当有多个数据存储时,将它们作为单个聚合存储呈现给托管对象上下文。
备忘录模式的实现
备忘录模式使用三个类 Memento
、Originator
和 CareTaker
。
Memento
包含了要被恢复的对象的状态。
@interface Memento : NSObject
@property (nonatomic,strong,readonly) NSString *state;
- (instancetype)initWithState:(NSString *)state;
@end
@implementation Memento
- (instancetype)initWithState:(NSString *)state
{
self = [super init];
if (self) {
_state = state;
}
return self;
}
@end
Originator
创建并在 Memento
对象中存储状态。
@interface Originator : NSObject
@property (nonatomic, strong) NSString *state;
@end
@implementation Originator
- (Memento *)saveStateToMemento{
return [[Memento alloc] initWithState:_state];
}
- (void)getStateFromMemento:(Memento *)memento{
_state = memento.state;
}
@end
Caretaker
对象负责从 Memento
中恢复对象的状态。
@interface CareTaker : NSObject
- (void)addMemento:(Memento *)memento;
- (Memento *)getMementoWithIndex:(int)index;
@end
@implementation CareTaker{
NSMutableArray <Memento *> * _mementoList;
}
- (instancetype)init
{
self = [super init];
if (self) {
_mementoList = [NSMutableArray array];
}
return self;
}
- (void)addMemento:(Memento *)memento{
[_mementoList addObject:memento];
}
- (Memento *)getMementoWithIndex:(int)index{
if (index < _mementoList.count) {
return [_mementoList objectAtIndex:index];
}
return nil;
}
@end
总结
很多时候我们总是需要记录一个对象的内部状态,可以通过一个备忘录类专门存储对象状态,以便在适当的时候恢复对象。保存程序的状态不需要什么特别奇妙的方法,任何简单有效的方法都可以,但是同时,保存信息应该只对原始程序有意义。原始程序应该是能够解码它所保存文档中的信息的唯一实体。