iOS备忘录设计模式

(-) 提出问题

我们在编程的时候,经常需要保存对象的一个状态,当需要的时候,可以恢复到这个状态。比如,我们使用Xcode进行编程时,假如编写失误(例如不小心误删除了几行代码),我们希望返回删除前的状态,便可以使用Ctrl+Z来进行返回。这时我们便可以使用备忘录模式来实现。

(二 )备忘录设计模式 简介

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将对象恢复到原先保存的的状态。——《设计模式》

通用类图如下:

1468660-db507e2ccc5aff28.jpg

使用场景:
当满足以下两个条件的时候,应当考虑使用这一模式。
1、需要保存一个对象(活某部分)在某一时刻的状态,这样以后就可以恢复先前的状态;
2、用于获取状态的接口,会暴露实现的细节,需要将其隐藏起来;

(二 )使用备忘录设计模式

通过一个简单的例子来实现这个设计模式。例子很简单,只是完成一个类的一个属性保存和恢复。

第1步 创建协议

创建协议的原因是因为备忘录存储的数据不一定是什么类型的,我们要让备忘录能存储很多类型的数据,需要让需要备忘的类实现一套统一的接口。
协议包含两个方法,一个获取当前状态的方法,和一个恢复状态的方法。需要使用备忘录的类在这两个方法里实现存储和恢复的逻辑。

#import <Foundation/Foundation.h>

@protocol MementoCenterProtocol <NSObject>

/*
 获得状态
 */
-(id)getStatus;
/*
 设置状态
 */
-(void)setStatus:(id)data;
@end
第2步 创建备忘录类

备忘录中心类只负责数据的存储和恢复。传过来的object必须是继承上面协议的对象,这样就可以调用协议里的方法获得需要备忘的数据了。类里有两个方法。
根据key保存状态

/**
*  保存备忘录
*
*  @param object object
*  @param key    key
*/
+(void)saveMementoObject:(id<MementoCenterProtocol>)object withKey:(NSString*)key{
   if (object==nil || key==nil) {
       return;
   }
   id  data = [object getStatus];
  
   NSData *tmpData = [FastCoder dataWithRootObject:data];
   
   // 进行存储
   if (tmpData) {
       
       [[NSUserDefaults standardUserDefaults] setObject:tmpData
                                                 forKey:key];
   }
}

根据key获得object状态数据

/**
 *  获得保存的状态数据
 *
 *  @param key key
 *
 *  @return 状态
 */
+(id)getMementObjectWithKey:(NSString*)key{
    if (key==nil) {
        return nil;
    }
    id data =  nil;
    NSData *tmpData = [[NSUserDefaults standardUserDefaults] objectForKey:key];
    
    if (tmpData) {
        
        data = [FastCoder objectWithData:tmpData];
    }
    
    return data;
    
    
}

这两个方法里面用到了一个类FastCoder的方法,FastCoder是一个Cocoa object和object graph的高性能二进制序列化格式,可以作为Property Lists和JSON的替代选择。FastCoder git地址

第3步 创建工具类

如果我们直接调用备忘录的方法的话,会暴露出我们实现的细节,也会暴露出我们要备忘的object。所以我们创建一个工具类,来再封装一层。这样我们就不会暴露具体的实现细节了。

/**
 *  备忘状态
 *
 *  @param key 键值
 */
- (void)saveStateWithKey:(NSString *)key;

/**
 *  恢复状态
 *
 *  @param key 键值
 */
- (void)recoverFromStateWithKey:(NSString *)key;

实现:

- (void)saveStateWithKey:(NSString *)key{
    
    if (key==nil) {
        return;       
    }
  
    id<MementoCenterProtocol> obj = (id<MementoCenterProtocol>)self;
    
    if ([obj respondsToSelector:@selector(getStatus)]) {

        [MementoCenter saveMementoObject:obj withKey:key];

    }
}
- (void)recoverFromStateWithKey:(NSString *)key{
    if (key==nil) {
        return;
    }
    
    id state = [MementoCenter getMementObjectWithKey:key];

    id<MementoCenterProtocol> obj = (id<MementoCenterProtocol>)self;

    if ([obj respondsToSelector:@selector(setStatus:)]) {
        
        [obj setStatus:state];

    }
}
第4步 创建测试类

测试类里只有一个字符串属性,我们来恢复这个属性。测试类要实现上面协议的方法。

-(id)getStatus{
    
    return self.valueStr.length? self.valueStr: @"当前运动:10.00KM";
}

-(void)setStatus:(id)data{
    if (data) {
        self.valueStr = (NSString*)data;
  
    }
}
第5步 测试
    TestView *texeView = [[TestView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];

    [self.view addSubview:texeView];

    texeView.valueStr = @"idage";
  
    NSLog(@"恢复前 ===%@",texeView.valueStr );
    //保存
    [texeView saveStateWithKey:@"test"];

    texeView.valueStr = @"idage163";

    //恢复
    [texeView recoverFromStateWithKey:@"test"];
    
    NSLog(@"恢复后 ===%@",texeView.valueStr );

这样我们就是实现了既能保存和恢复状态,也不会暴露保存和恢复的细节。

(四)鸣谢

这篇文章是看过 YouXianMing老师 的教程后,得到的启发并重构自己项目代码后写的总结。希望对大家有点帮助。在此感谢YouXianMing老师。

代码github下载地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容