设计模式 - 备忘录
备忘录模式很简单,就是存储对象,然后支持恢复对象到之前的某个状态,玩过游戏的,一定懂得存档一说,备忘录就是对对象的存档与管理。
效果:
这个需要配合FastCoder使用,请自行到Github上去搜索源码FastCoder源码^_^!
源码:
Model.h 与 Model.m
//
// Model.h
// MementoPattern
//
// Created by YouXianMing on 15/1/3.
// Copyright (c) 2015年 YouXianMing. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Model : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *age;
/**
* 初始化方法
*
* @param key 用来标示对象唯一性
*
* @return 对象
*/
- (instancetype)initWithKey:(NSString *)key;
/**
* 从某个状态恢复
*
* @param slot 状态槽位(第几个存档位置)
* @param key 标示字符串(保证存档唯一)
*
* @return 存档的对象,如果对象不存在,则重新创建
*/
+ (id)recoverFromSlot:(NSInteger)slot key:(NSString *)key;
/**
* 存储到slot当中(按照数组的顺序)
*/
- (void)store;
@end
//
// Model.m
// MementoPattern
//
// Created by YouXianMing on 15/1/3.
// Copyright (c) 2015年 YouXianMing. All rights reserved.
//
#import "Model.h"
#import "FastCoder.h"
#import "NSString+File.h"
@interface Model ()
@property (nonatomic, strong) NSString *key;
@property (nonatomic, strong) NSMutableArray *slotInfoArray;
@end
@implementation Model
- (instancetype)init
{
self = [super init];
if (self) {
self.key = @"Default";
}
return self;
}
- (instancetype)initWithKey:(NSString *)key {
Model *model = [Model new];
model.key = key;
return model;
}
+ (id)recoverFromSlot:(NSInteger)slot key:(NSString *)key {
if (key == nil) {
key = @"Default";
}
NSString *arrayPath = [[@"/Documents" path] stringByAppendingString:[NSString stringWithFormat:@"/%@_array", key]];
NSString *objectPath = [[@"/Documents" path] stringByAppendingString:[NSString stringWithFormat:@"/%@_%ld", key, (long)slot]];
id object = nil;
NSArray *array = [FastCoder objectWithData:[self dataWithPath:arrayPath]];
if (array.count > slot && slot >= 0) {
object = [FastCoder objectWithData:[self dataWithPath:objectPath]];
}
return object;
}
- (void)store {
if (self == nil) {
return;
}
self.slotInfoArray = [FastCoder objectWithData:[self dataWithPath:[self arrayPath]]];
if (self.slotInfoArray.count == 0) {
[[FastCoder dataWithRootObject:self] writeToFile:[self filePathAtSlot:0]
atomically:YES];
self.slotInfoArray = [NSMutableArray array];
[self.slotInfoArray addObject:@""];
[[FastCoder dataWithRootObject:self.slotInfoArray] writeToFile:[self arrayPath]
atomically:YES];
} else {
[[FastCoder dataWithRootObject:self] writeToFile:[self filePathAtSlot:self.slotInfoArray.count]
atomically:YES];
[self.slotInfoArray addObject:@""];
[[FastCoder dataWithRootObject:self.slotInfoArray] writeToFile:[self arrayPath]
atomically:YES];
}
NSLog(@"store sucess!");
}
#pragma mark - private method
- (NSString *)filePathAtSlot:(NSInteger)slot {
NSString *path = [[@"/Documents" path] stringByAppendingString:[NSString stringWithFormat:@"/%@_%ld", self.key, (long)slot]];
return path;
}
- (NSString *)arrayPath {
NSString *path = [[@"/Documents" path] stringByAppendingString:[NSString stringWithFormat:@"/%@_array", self.key]];
return path;
}
- (NSData *)dataWithPath:(NSString *)path {
return [NSData dataWithContentsOfFile:path];
}
+ (NSData *)dataWithPath:(NSString *)path {
return [NSData dataWithContentsOfFile:path];
}
@end
NSString+File.h 与 NSString+File.m
//
// NSString+File.h
// Category
//
// Created by YouXianMing on 14-8-29.
// Copyright (c) 2014年 YouXianMing. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSString (File)
// 沙盒路径
- (NSString *)path;
/*
/Documents
/Library/Caches
/Library/Preferences
/tmp
*/
// bundle文件
- (NSString *)bundleFile;
// 检测文件或者文件夹是否存在
- (BOOL)exist;
// 创建文件夹
- (BOOL)createFolder;
// 是否是文件夹
- (BOOL)isDirectory;
// 复制到这个路径
- (BOOL)copyTo:(NSString *)path;
// 移动到这个路径
- (BOOL)moveTo:(NSString *)path;
// 删除文件
- (BOOL)remove;
// 遍历出文件夹中的文件
- (NSArray *)enumeratorFolder;
// 遍历出文件夹并在block中查看
- (void)enumeratorFolderEach:(void (^)(NSString *path))block;
// 文件信息
- (NSDictionary *)fileInfo;
// 文件大小
- (int)fileSize;
@end
//
// NSString+File.m
// Category
//
// Created by YouXianMing on 14-8-29.
// Copyright (c) 2014年 YouXianMing. All rights reserved.
//
#import "NSString+File.h"
@implementation NSString (File)
- (NSString *)path
{
return [NSHomeDirectory() stringByAppendingPathComponent:self];
}
- (NSString *)bundleFile
{
return [[NSBundle mainBundle] pathForResource:self
ofType:nil];
}
- (BOOL)exist
{
return [[NSFileManager defaultManager] fileExistsAtPath:[NSHomeDirectory() stringByAppendingPathComponent:self]
isDirectory:NO];
}
- (BOOL)createFolder
{
return [[NSFileManager defaultManager] createDirectoryAtPath:[NSHomeDirectory() stringByAppendingPathComponent:self]
withIntermediateDirectories:YES
attributes:nil
error:nil];
}
- (BOOL)isDirectory
{
BOOL isDirectory = NO;
[[NSFileManager defaultManager] fileExistsAtPath:[NSHomeDirectory() stringByAppendingPathComponent:self]
isDirectory:&isDirectory];
return isDirectory;
}
- (BOOL)copyTo:(NSString *)path
{
return [[NSFileManager defaultManager] copyItemAtPath:[NSHomeDirectory() stringByAppendingPathComponent:self]
toPath:[NSHomeDirectory() stringByAppendingPathComponent:path]
error:nil];
}
- (BOOL)moveTo:(NSString *)path
{
return [[NSFileManager defaultManager] moveItemAtPath:[NSHomeDirectory() stringByAppendingPathComponent:self]
toPath:[NSHomeDirectory() stringByAppendingPathComponent:path]
error:nil];
}
- (BOOL)remove
{
return [[NSFileManager defaultManager] removeItemAtPath:[NSHomeDirectory() stringByAppendingPathComponent:self]
error:nil];
}
- (NSArray *)enumeratorFolder
{
if ([self isDirectory])
{
NSMutableArray *storeArray = [NSMutableArray array];
NSString *docsDir = [NSHomeDirectory() stringByAppendingPathComponent:self];
NSFileManager *localFileManager = [[NSFileManager alloc] init];
NSDirectoryEnumerator *dirEnum = [localFileManager enumeratorAtPath:docsDir];
NSString *file;
while ((file = [dirEnum nextObject]))
{
[storeArray addObject:[[NSHomeDirectory() stringByAppendingPathComponent:self] stringByAppendingPathComponent:file]];
}
return storeArray;
}
else
{
return nil;
}
}
- (void)enumeratorFolderEach:(void (^)(NSString *path))block
{
if ([self isDirectory])
{
NSMutableArray *storeArray = [NSMutableArray array];
NSString *docsDir = [NSHomeDirectory() stringByAppendingPathComponent:self];
NSFileManager *localFileManager = [[NSFileManager alloc] init];
NSDirectoryEnumerator *dirEnum = [localFileManager enumeratorAtPath:docsDir];
NSString *file;
while ((file = [dirEnum nextObject]))
{
[storeArray addObject:[self stringByAppendingPathComponent:file]];
}
[storeArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
block(obj);
}];
}
}
- (NSDictionary *)fileInfo
{
return [[NSFileManager defaultManager] attributesOfItemAtPath:[NSHomeDirectory() stringByAppendingPathComponent:self]
error:nil];
}
- (int)fileSize
{
return [[[[NSFileManager defaultManager] attributesOfItemAtPath:[NSHomeDirectory() stringByAppendingPathComponent:self]
error:nil] \
objectForKey:@"NSFileSize"] intValue];
}
@end
控制器源码:
//
// ViewController.m
// MementoPattern
//
// Created by YouXianMing on 15/1/3.
// Copyright (c) 2015年 YouXianMing. All rights reserved.
//
#import "ViewController.h"
#import "NSString+File.h"
#import "Model.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Model *model_01 = [Model new];
model_01.name = @"YouXianMing";
model_01.age = @"27";
[model_01 store]; // 存快照
Model *model_02 = [Model new];
model_02.name = @"QiuLiang";
model_02.age = @"28";
[model_02 store]; // 存快照
Model *model_03 = [Model new];
model_03.name = @"XiaoMing";
model_03.age = @"100";
[model_03 store]; // 存快照
// Model *test_model_01 = [Model recoverFromSlot:0 key:nil];
// NSLog(@"%@ %@", test_model_01.name, test_model_01.age);
//
// Model *test_model_02 = [Model recoverFromSlot:1 key:nil];
// NSLog(@"%@ %@", test_model_02.name, test_model_02.age);
//
// Model *test_model_03 = [Model recoverFromSlot:2 key:nil];
// NSLog(@"%@ %@", test_model_03.name, test_model_03.age);
}
@end
几个关键的地方:
原理其实非常简单,就是将对象写文件,然后从文件从恢复出对象,但一定要有管理的功能,本例中并没有处理如何删除存档,其实存档可以做成堆栈或者队列模式,这个因需求而已,本处本人只是抛砖引玉,简单介绍下备忘录设计模式!