定义
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
解决问题
所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
角色
1、Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。Originator可以根据需要决定Memento存储自己的哪些内部状态。
2、Memento(备忘录):负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator却可看到备忘录的宽接口,允许它访问返回到先前状态所需要的所有数据。
3、Caretaker(管理者):负责备忘录Memento,不能对Memento的内容进行访问或者操作。
使用场景
很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃。
解决办法
通过一个备忘录类专门存储对象状态。
应用实例
1、后悔药。 2、打游戏时的存档。 3、Windows 里的 ctri + z。 4、IE 中的后退。
优缺点
优点
1、给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。
2、实现了信息的封装,使得用户不需要关心状态的保存细节。
缺点
消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。
注意事项
1、为了符合迪米特原则,还要增加一个管理备忘录的类。
2、为了节约内存,可使用原型模式+备忘录模式。
模拟场景
游戏记录关卡
备忘录UML 图
1.Originator 生成需要备份的片段memento
2.Caretake 保存生成的memento
3.要是Originator 读档,就找Caretake 读取相关片段memento 将其还原就可以了。
简单代码
#import <Foundation/Foundation.h>
#import "Memento.h"
@interface GameLevel : NSObject
-(void)add:(Memento*)memento;
-(Memento *)get:(NSInteger)index;
@end
#import "GameLevel.h"
@interface GameLevel()
@property (nonatomic,strong) NSMutableArray *mementos;
@end
@implementation GameLevel
- (instancetype)init
{
self = [super init];
if (self) {
self.mementos = [NSMutableArray new];
}
return self;
}
-(void)add:(Memento*)memento{
[self.mementos addObject:memento];
}
-(Memento *)get:(NSInteger)index{
if (index<self.mementos.count) {
return [self.mementos objectAtIndex:index];
}
return 0;
}
@end
#import <Foundation/Foundation.h>
#import "Memento.h"
@interface Game : NSObject
@property (nonatomic,assign) int level;
-(Memento *)saveStateToMemento;
-(void)getStateFromMemento:(Memento*)memento;
@end
#import "Game.h"
@implementation Game
-(Memento *)saveStateToMemento{
Memento * me=[Memento new];
me.level = self.level;
return me;
}
-(void)getStateFromMemento:(Memento*)memento{
self.level = memento.level;
}
@end
#import <Foundation/Foundation.h>
@interface Memento : NSObject
@property (nonatomic,assign) int level;
@end
#import "Memento.h"
@implementation Memento
@end
测试代码
Game * game = [Game new];
GameLevel * level= [GameLevel new];
game.level = 3;
[game saveStateToMemento];
game.level = 4;
[level add:[game saveStateToMemento]];
game.level = 5;
[level add:[game saveStateToMemento]];
[game getStateFromMemento: [level get:0]];
NSLog(@"获取第一次位置的state %d",game.level);
[game getStateFromMemento: [level get:1]];
NSLog(@"获取第二次位置的state %d",game.level);
测试结果
2018-04-11 10:51:08.053994+0800 行为型设计模式-备忘录模式[63572:8555092] 获取第一次位置的state 4
2018-04-11 10:51:08.054218+0800 行为型设计模式-备忘录模式[63572:8555092] 获取第二次位置的state 5
下一篇讲解