iOS备忘录设计模式

作者: idage | 来源:发表于2016-11-09 20:50 被阅读145次

(-) 提出问题

我们在编程的时候,经常需要保存对象的一个状态,当需要的时候,可以恢复到这个状态。比如,我们使用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下载地址

相关文章

网友评论

  • 21028c2ec73c:本司急需请技术大佬上架apple store马甲包,麻烦添加我的QQ:3366817827 本人冒昧在此评论回复望见谅!
  • 29f6204fa90f: :wink: 呦!还不错呦!

本文标题:iOS备忘录设计模式

本文链接:https://www.haomeiwen.com/subject/sjftpttx.html