备忘录设计模式

备忘录模式

备忘录设计模式将一个对象的内部状态进行捕捉并外部化,换句话说就是你将你的东西保存在某个地方。以后这个外部话的转台不需要借助封装就可以被回复,也就是私有的数据还是私有的。

如何使用备忘录设计模式

接下来将下面两个方法添加在ViewController.m中

- (void)saveCurrentState  
   
{  
   
    [[NSUserDefaultsstandardUserDefaults] setInteger:currentAlbumIndexforKey:@"currentAlbumIndex"];  
   
    
   
}  
   
    
   
- (void)loadPreviousState  
   
{  
    currentAlbumIndex = [[NSUserDefaultsstandardUserDefaults]integerForKey:@"currentAlbumIndex"];  
   
    [selfshowDataForAlbumAtIndex:currentAlbumIndex];  
   
}

    saveCurrentState将当前的album的index保存到NSUserDefaults,NSUserDefaults是一个iOS为了保存应用的具体的设置和数据而提供的一个标准的数据存储的类。

    loadPreviousState加载了先前保存的index这并不是完整的备忘录设计模式,但是你现在达到了目的。

    现在添加下面这行代码到ViewController的viewDidLoad中的在scroller被初始化的代码之前。

    [self loadPreviousState];

    这会在app启动的时候加载先前被保存的状态。但是你在那里保存从后台回来的的app的状态。你要使用通知去完成这个任务。iOS在app被放到后台的时候会发送一个UIApplicationDidEnterBackgroundNotification的通知,你可以使用这个通知去调用saveCurrentState,是不是很方便啊?

    加入下面的这行代码到ViewDidLoad的结尾。

    [[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(saveCurrentState)name:UIApplicationDidEnterBackgroundNotificationobject:nil];

    当app将要被挂起到后台的时候,ViewController就会自动地调用saveCurrentState去保存状态。

    现在添加下面的代码:

    -(void)dealloc  
       
    {  
       
        [[NSNotificationCenterdefaultCenter]removeObserver:self];  
       
    }

      这会保证当ViewController被deallocate时候将这个累中从观察者去移去。

      编译运行你的应用,拖动到某一张album,使用Command+shift+H去将app设置到后台,然后关闭你的app,重新启动,看看原先你拖动到的那张图片是不是设置在中间。

      看起来这个album的数据是对的嘛,但是这个scroller并没有将正确的album设置在中心,这是怎么回事?

      这是因为这个可选的方法: initialViewIndexForHorizontalScroller的意义所在,因为你没有实现这个方法,所以它总是被设置在默认的第一张。

      去修正它,添加下面的代码到ViewController中:

      - (NSInteger)initialViewIndexForHorizontalScroller:(HorizontalScroller *)scroller  
         
      {  
         
          returncurrentAlbumIndex;  
         
      }

      现在这个HorizontalScroller的第一张数一被设置成表示album位置的currentAlbumIndex,这是一个很好的方法去确保这个app保持个人化和可重用的双重便利。

      再次运行你的app,滚动一个 app

      ,停止app,再启动,确保问题已经被解决。

      如果你看看你的PersistencyManager的init方法,你会注意到这个album的数据被写死了,而每次当PersistencyManager被创建的时候就被重新创建,但是是不是只创建一次albums的列表然后将它们保存在一个文件中更好呢?但是你怎么将你的Album数据保存再一个文件中呢?

      一个选择就是使用Album的property属性,将它们保存再一个plist文件中然后当需要的时候重新去创建Album实例,这不是最好的选择,因为它需要你去写一个具体的依赖于再每一个类中的数据或者properties的代码,例如说如果你后来创建了一个具有不同的属性的Movie的类,那保存和重新读取数据将要一个新的代码去完成。

      此外,你不能将一个私有变量保存在每一个类的实例中因为它们是不能被外界所访问的。这就是苹果公司创建这个Achiving机制的原因。

      Achiving

      Achiving是苹果公司具体实现备忘录模式之一。它将一个对象转换成一个可以被保存后面可以回复但是不需要将私有变量暴露给外部类。

      如何使用Achiving

      首先你需要去通过遵守NSCoding这个协议表明这个Album类可以被压缩打开Album.h然后将它变成遵守这个协议:

      @interface Album :NSObject <NSCoding>

      然后添加下面的代码到Album.m中:

      - (void)encodeWithCoder:(NSCoder *)aCoder  
         
      {  
         
          [aCoder encodeObject:_titleforKey:@"title"];  
         
          [aCoder encodeObject:_artistforKey:@"artist"];  
         
          [aCoder encodeObject:_coverUrlforKey:@"coverUrl"];  
         
          [aCoder encodeObject:_yearforKey:@"year"];  
         
          [aCoder encodeObject:_genreforKey:@"genre"];  
         
      }  
         
          
         
      - (id)initWithCoder:(NSCoder *)aDecoder  
         
      {  
         
          if (self = [superinit]) {  
         
                
         
              _title = [aDecoder decodeObjectForKey:@"title"];  
         
              _genre = [aDecoder decodeObjectForKey:@"genre"];  
         
              _year = [aDecoder decodeObjectForKey:@"year"];  
         
              _artist = [aDecoder decodeObjectForKey:@"artist"];  
         
              _coverUrl = [aDecoder decodeObjectForKey:@"coverUrl"];  
         
          }  
         
            
         
          returnself;  
         
      }

        你调用encodeWithCoder当你压缩一个类的实例变量的时候,相反你调用initWithCoder当你解压一个实例去创建一个Album的实例的时候,很简单却很强大。

        现在这个Album类可以被压缩那就添加时机保存和重载albums的列表的类。

        添加下面的方法声明到你的PersistencyManager.h中:

        -(void)saveAlbums;

        这将会在调用保存albums数据的时候被调用,下面添加这个实现到PersistencyManager.m中

        -(void)saveAlbums  
           
        {  
           
            NSString *path = [NSHomeDirectory() stringByAppendingString:@"/Documents/,albums.bin"];  
           
            NSData *data = [NSKeyedArchiverarchivedDataWithRootObject:albums];  
           
            [data writeToFile:path atomically:YES];  
           
        }

        NSKeyedArchiver黄这个album数组压缩到一个albums.bin的文件中。当你u压缩一个包含其他对象的对象时,那么这个Archiver会自动的尝试去递归地压缩子对象和子对象的子对象等等。在这个实例中,这个archival开始于albums-这时一个Album各种实例的数组,因为NSArray和Album都支持NSCoping接口,所以这个数组被自动的压缩了。

        现在替换PersistencyManager.m文件中的init文件。

        - (id)init     
        {  
           
            self = [superinit];  
           
            if (self) {  
           
                NSString *path = [NSHomeDirectory() stringByAppendingString:@"/Documents/,albums.bin"];  
           
                NSData *data = [NSDatadataWithContentsOfFile:path];  
           
                albums = [NSKeyedUnarchiverunarchiveObjectWithData:data];  
           
                if (!albums) {  
           
                     albums = [NSMutableArrayarrayWithArray:@[[[Albumalloc] initWithTitle:@"Best of Bowie"artist:@"David Bowie"coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_david%20bowie_best%20of%20bowie.png"year:@"1992"],[[Albumalloc] initWithTitle:@"It‘s MyLife"artist:@"NoDoubt"coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_no%20doubt_its%20my%20life%20%20bathwater.png"year:@"2003"],[[Albumalloc] initWithTitle:@"NothingLike The Sun"artist:@"Sting"coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_sting_nothing%20like%20the%20sun.png"year:@"1999"],[[Albumalloc] initWithTitle:@"Staringat the Sun"artist:@"U2"coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_u2_staring%20at%20the%20sun.png"year:@"2000"],[[Albumalloc] initWithTitle:@"AmericanPie"artist:@"Madonna"coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_madonna_american%20pie.png"year:@"2000"]]];  
           
                    [selfsaveAlbums];  
           
                }  
           
                 
           
            }  
           
            returnself;  
           
        }

          在这个新的代码中NSKeyedUnarchiver从文件中加载这个album的数据,如果存在的话,如果不存在,它就会创建一个album数据然后立刻保存它让下次启动app的时候使用。

          你也想要去在每次app进入到后台的时候保存album的数据,这似乎不需要但是如果后面你想要添加一个去改变album数据的选择呢?然后你想要去确保所有的变化都被保存了的。添加下面的方法声明到LibraryAPI.h中;

          -(void)saveAlbums;

          既然主要的application访问所有的服务都是通过LibraryAPI,这就是应用怎么样让PersistencyManager去知道它是否需要保存数据,现在添加下面的方法实现到LibraryAPI.m中。

          - (void)saveAlbums  
             
          {  
             
              [managersaveAlbums];  
             
          }

            这个代码仅仅传递了一个去让PersistencyManager去保持albums的一个调用。

            然后添加下面这行代码到ViewController.m的saveCurrentState 中

            [[LibraryAPIsharedInstance]saveAlbums];

            上面的代码使用LibraryAPI去当ViewCOntroller想要去保存数据的时候触发保存album数据的方法。

            现在变异你的app去确保编译通过。

            不幸的是,没有什么简单的方法去检查数据的固话是否完全正确,你可以在模拟器的Mocunments文件夹下面去检查album数据文件是创建的,但是为了企业看到温和的改变你需要去添加一个可以去改变album数据的草种。

            与其去改变数据,如果你添加一个去删除你不想让它存在在albums中的一个album的选择项的话是不是更好?此外添加一个撤销的操作以免被误删除呢?

            这就提供了一个很好的机会去介绍最后一个设计模式:命令模式

            时间: 2024-10-12 13:04:01

            备忘录设计模式的相关文章

            Design Pattern Memo 备忘录设计模式

            本设计模式就是简单地记录当前状态,然后利用记录的数据恢复. 比如首先我们有一个类,类需要记录当前状态进行相关的工作的: class Memo; class Human { public: string state; Memo *makeMemo(); void restroDataFromMemo(Memo *m); void show() { cout<<"State: "<<state<<endl; } }; 这里面的state可以是任意定义的数

            iOS设计模式--备忘录设计模式与命令设计模式

            何为备忘录模式? 在响应某些事件时,应用程序需要保存自身的状态,比如当用户保存文档或程序退出时.例如,游戏退出之前,可能需要保存当前会话的状态,如游戏等级.敌人数量.可用武器的种类等.游戏再次打开时,玩家可以从离开的地方接着玩.很多时候,保存程序的状态真的不需要什么特别巧妙的方法.任何简单有效的方法都可以,但是同时,保存信息应该只对原始程序有意义.原始程序应该是能够解码它所保存文档中的信息的唯一实体.这就是备忘录模式应用于游戏.文字处理等程序的软件设计中的方式,这些程序需要保存当前上下文的复杂状

            Memento模式(备忘录设计模式)

            Memento模式? 使用面向对象编程的方式实现撤销功能时,需要事先保存实例的相关状态信息.然后,在撤销时,还需要根据所保存的信息将实例恢复至原来的状态.这个时候你需要使用Memento设计模式.(以及实例实现对状态的保存) 关键字: 1.·Undo(撤销) 2.·Redo(重做) 3.·History(历史记录) 4.·Snapshot(快照) 破坏封装性: 将依赖于实例内部结构的代码分散地编写在程序中的各个地方,导致程序变得难以维护. 宽窄接口 wide interface--宽接口(APl

            设计模式(31)-----行为型模式-----备忘录设计模式

            备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象.备忘录模式属于行为型模式. 介绍 意图:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态. 主要解决:所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态. 何时使用:很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"

            超简易复制Model对象(为后续备忘录设计模式博文做铺垫)

            复制整个Model需要实现NSCopy协议,可以想象是非常麻烦的一件事情,今天我跟大家分享一个不需要你做任何操作的复制Model对象的方法,不过,首先你得先去下载开源代码FastCoder辅助才行. 源码如下: NSObject+ObjectCopy.h 与 NSObject+ObjectCopy.m // // NSObject+ObjectCopy.h // FastCoder // // Created by YouXianMing on 15/1/3. // Copyright (c)

            设计模式 - 备忘录

            备忘录模式很简单,就是存储对象,然后支持恢复对象到之前的某个状态,玩过游戏的,一定懂得存档一说,备忘录就是对对象的存档与管理. 效果: 这个需要配合FastCoder使用,请自行到Github上去搜索源码FastCoder源码^_^! 源码: Model.h 与 Model.m // // Model.h // MementoPattern // // Created by YouXianMing on 15/1/3. // Copyright (c) 2015年 YouXianMing. Al

            Java设计模式菜鸟系列(十九)备忘录模式建模与实现

            转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/40018967 备忘录模式(Memento): 主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象. 一.uml建模: 二.代码实现 /** * 备忘录模式(Memento):主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象 * * 示例:原始类--> 创建.恢复备忘录 */ class Original { private String state; public Or

            [转] Android中的设计模式-备忘录模式

            转自Android中的设计模式-备忘录模式 定义 备忘录设计模式的定义就是把对象的状态记录和管理委托给外界处理,用以维持自己的封闭性. 比较官方的定义 备忘录模式(Memento Pattern)又叫做快照模式(Snapshot Pattern)或Token模式,是GoF的23种设计模式之一,属于行为模式. 定义:在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 角色 笔记本:很多的内部状态需要被建立一个备忘录来管理,创建和取出

            单例、观察者、代理、备忘录、工厂

            单例.观察者.代理.备忘录.工厂 分类: java 2014-07-03 10:13 364人阅读 评论(0) 收藏 举报 一.Singleton单例模式 Singleton单例模式是最简单的设计模式,它的主要作用是保证在程序运行生命周期中,使用了单类模式的类只能有一个实例对象存在. 1.饱汉模式,声明时就创建实例对象 [java] view plaincopy public class Singleton1 { public static final Singleton1 instance =