这个模式的产生是用来解决一种场景,为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。
看到这个场景我们可能想到的是,把用户的状态存下来。那么如何再不破坏封装性的前提下,设计一个备忘中心来统一的调度呢?
那么接下来我们就需要来设计一个MementoCenter备忘中心。
首先我们定义一个协议MementoCenterPotocol,里面包含了两个方法,一个是currentState的方法,一个是recoverFromState状态。
@protocol MementoCenterPotocol <NSObject>
- (id)currentState;
- (void)recoverFromState:(id)state;
@end
再来设计单独的类,MementoCenter,包含saveMementoObject和mementoObjectWithKey的方法,这个类是用来存储和取出备忘状态的类。
@implementation MementoCenter
+ (void)saveMementoObject:(id<MementoCenterPotocol>)object withKey:(NSString *)key {
NSParameterAssert(object);
NSParameterAssert(key);
//获取data,通过potocol确定object的那些property需要存储
id data = [object currentState];
NSData *tmpData = [FastCoder dataWithRootObject:data];
//存储data
if (tmpData) {
[[NSUserDefaults standardUserDefaults] setObject:tmpData forKey:key];
}
}
+ (id)mementoObjectWithKey:(NSString *)key {
NSParameterAssert(key);
id data = nil;
NSData *tmpData = [[NSUserDefaults standardUserDefaults] objectForKey:key];
if (tmpData) {
data = [FastCoder objectWithData:tmpData];
}
return data;
}
@end
然后我们需要给nsobject加一个分类,目的是为了给所有的nsobject对象都添加这个备忘的功能,需要保证
所有的调用的这两个方法的对象都遵循了MementoCenterPotocol的协议。
@implementation NSObject (MementoCenter)
- (void)saveStateWithKey:(NSString *)key {
NSParameterAssert(key);
id <MementoCenterPotocol> obj = (id <MementoCenterPotocol>)self;
if ([obj respondsToSelector:@selector(currentState)]) {
[MementoCenter saveMementoObject:obj withKey:key];
}
}
- (void)recoverFromStateWithKey:(NSString *)key {
NSParameterAssert(key);
id <MementoCenterPotocol> obj = (id <MementoCenterPotocol>)self;
if ([obj respondsToSelector:@selector(recoverFromStateWithKey:)]) {
id state = [MementoCenter mementoObjectWithKey:key];
if (state) {
[obj recoverFromState:state];
}
}
}
@end
最后一步就是来使用他了。我们来对一个view进行备忘和恢复操作,设计一个view,并且遵守MementoCenterPotocol
@interface DemoView : UIView <MementoCenterPotocol>
@end
@implementation CustomView
//返回demoView的frame
- (id)currentState {
return @{@"frame" : NSStringFromCGRect(self.frame)};
}
//恢复CustomView的frame
- (void)recoverFromState:(id)state {
NSDictionary *data = state;
[UIView animateWithDuration:3.f animations:^{
self.frame = CGRectFromString(data[@"frame"]);
}];
}
@end
使用,先存储当前状态,再恢复状态。
- (void)test1 {
_demoView.frame = CGRectMake(100, 100, 100, 100);
[_demoView saveStateWithKey:@"demoView"];
NSLog(@"%@", _demoView);
}
- (void)test2 {
//注意log
NSLog(@"%@", _demoView);
NSLog(@"*******************");
[_demoView recoverFromStateWithKey:@"demoView"];
NSLog(@"%@", _demoView);
}
网友评论