备忘录模式:如果需要对象能返回之前的状态就使用备忘录模式。
备忘录模式是行为性模式之一。
备忘录模式包含原发器(Originator),备忘录(Memento),负责人(Caretaker)三个角色。

原发器是备忘录的发起者,用来生成一条备忘录,备忘录用来存储原发器的状态。
负责人用于存储备忘录。
举个栗子
很多人经常玩游戏,很多游戏都有保存进度这个说法,可能你进了某个图,如果不保存状态,那么死后装备丢失,金币丢失等等这样一些不合理的情况。
所以我们这里模拟一个游戏的栗子
原发器
#import <Foundation/Foundation.h>
@class PlayerMemento;
NS_ASSUME_NONNULL_BEGIN
@interface Player : NSObject
@property (nonatomic ,strong)NSString * name;
@property (nonatomic ,strong)NSString * sex;
@property (nonatomic ,strong)NSString * idnum;
@property (nonatomic ,assign)NSInteger experiense;
@property (nonatomic ,assign)NSInteger level;
@property (nonatomic ,assign)NSInteger gold;
@property (nonatomic ,assign)NSInteger ingots;
@property (nonatomic ,assign)NSInteger blod;
@property (nonatomic ,assign)NSInteger magicPower;
-(PlayerMemento *)createPlayerMemento;
-(void)setPlayerMemento:(PlayerMemento *)menmento;
@end
NS_ASSUME_NONNULL_END
#import "Player.h"
#import "PlayerMemento.h"
@implementation Player
-(PlayerMemento *)createPlayerMemento {
PlayerMemento * menmento = [[PlayerMemento alloc] init];
menmento.experiense = self.experiense;
menmento.level = self.level;
menmento.gold = self.gold;
menmento.ingots = self.ingots;
menmento.blod = self.blod;
menmento.magicPower = self.magicPower;
return menmento;
}
-(void)setPlayerMemento:(PlayerMemento *)menmento {
self.experiense = menmento.experiense;
self.level = menmento.level;
self.gold = menmento.gold;
self.ingots = menmento.ingots;
self.blod = menmento.blod;
self.magicPower = menmento.magicPower;
}
- (NSString *)description
{
NSDictionary * info = @{@"experiense":@(self.experiense),
@"level":@(self.level),
@"gold":@(self.gold),
@"ingots":@(self.ingots),
@"blod":@(self.blod),
@"magicPower":@(self.magicPower),
};
return [NSString stringWithFormat:@"<%@:%p,%@>",[self class],self,info];
}
@end
备忘录 .m文件不需要处理任何逻辑,这里只做一个临时的存储
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface PlayerMemento : NSObject
@property (nonatomic ,assign)NSInteger experiense;
@property (nonatomic ,assign)NSInteger level;
@property (nonatomic ,assign)NSInteger gold;
@property (nonatomic ,assign)NSInteger ingots;
@property (nonatomic ,assign)NSInteger blod;
@property (nonatomic ,assign)NSInteger magicPower;
@end
NS_ASSUME_NONNULL_END
careTacker 负责人处理存储逻辑,这里用单例模拟数据库存储逻辑。正确逻辑应该采用数据库存储,避免重新进入应用后数据丢失
#import <Foundation/Foundation.h>
@class PlayerMemento;
NS_ASSUME_NONNULL_BEGIN
@interface PlayerCareTacker : NSObject
+(instancetype)getInstance;
-(void)savePlayerWithIdNum:(NSString *)idNum playerMemento:(PlayerMemento *)memento;
-(PlayerMemento *)getPlayerWithIdNum:(NSString *)idNum;
@end
NS_ASSUME_NONNULL_END
结果演示
#import "ViewController.h"
#import "Player.h"
#import "PlayerMemento.h"
#import "PlayerCareTacker.h"
@interface ViewController ()
@property (nonatomic ,strong)Player * player;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Player * player = [[Player alloc] init];
player.name = @"小卤蛋来玩耍";
player.sex = @"女";
player.idnum = @"000001";
player.experiense = 12000;
player.level = 11;
player.gold = 3000000;
player.ingots = 12000;
player.blod = 14000;
player.magicPower = 500;
NSLog(@"%@",player);
PlayerMemento * memento = [player createPlayerMemento];
PlayerCareTacker * careTacker = [PlayerCareTacker getInstance];
[careTacker savePlayerWithIdNum:player.idnum playerMemento:memento];
_player = player;
[self playerAttackBooss:player];
}
-(void)playerAttackBooss:(Player *)player {
NSLog(@"小卤蛋遇到了大boss,一场大战后小卤蛋不幸阵亡");
player.experiense = 12000;
player.level = 11;
player.gold = 10000;
player.ingots = 1000;
player.blod = 1;
player.magicPower = 1;
NSLog(@"%@",player);
[self showDeathCover];
}
//展示死亡后的画面
-(void)showDeathCover {
UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(0, 200, 375, 200);
btn.backgroundColor = [UIColor redColor];
[btn setTitle:@"读取存档" forState:0];
[btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
-(void)btnClick:(UIButton *)btn {
PlayerCareTacker * careTacker = [PlayerCareTacker getInstance];
PlayerMemento * memento = [careTacker getPlayerWithIdNum:_player.idnum];
[_player setPlayerMemento:memento];
NSLog(@"%@",_player);
}
@end
运行后终端显示运行结果

优点
1.将被存储的状态放在外面,不和关键的对象混在一起便于维护内聚
2.保持关键对象的数据封装
3.提供了容易实现的恢复能力
缺点
1.存/取状态的过程可能会非常耗时
网友评论