温故知新(8)——备忘录模式

概述

先从面向对象的三大特征之一封装说起。面向对象的封装简单点说就是把状态(数据)和行为(操作这些数据的方法)放到一起,构成一个单元,通常叫做类。一个对象的行为是事先确定好的(静态)一些脚本,如果对象的状态相同,对象看起来就是一样的。所以当我们需要把一个对象的某一时刻保存起来,那么只需要保存它在那个时刻的状态;相反需要恢复对象到某一时刻时,只需恢复它在那个时刻的状态。这就是备忘录模式的原理。

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

上面是GOF对备忘录模式的意图描述,非常清楚,内部状态保存到外部,再从外部恢复对象。

实现时我们通常把需要保存起来的状态封装为一个对象,用这个对象作为一个信息的载体,保存或恢复。出于避免外界对这些信息进行窜改,有必要对这个信息载体进行一个抽象,让外界只知道这是一个信息载体,而不知道具体承载了什么内容(窄接口);而内部可以获得载体所载有的全部信息(宽接口)。

备忘录模式常用来实现“撤销/重做”。

结构

备忘录模式的类图:

备忘录

模式的参与者只有三个,相对简单。

1、作为对象状态信息载体的备忘录对象——IMemento、Memento,其中IMemento为对外的窄接口,而具体实现Memento则是对内的宽接口;

2、需要保存和恢复状态的对象,成为原发器——Originator;

3、管理和持有备忘录的备忘录负责人——Caretaker;

示例

有一个电子书阅读器,人们可以用它来阅读电子文档。阅读器提供了书签的功能,用户可以保存书签,也可以从使用一个书签使阅读器变为建立书签时的状态。我们简化一下,假设阅读器可以从书名和书的页码两个参数确定自身状态。

上面的需求很符合备忘录模式,书签可以看作备忘录对象,阅读器可以看作原发器,而隐含的书签管理结构可以作为负责人。

1、定义备忘录接口IBookmark(对外窄接口)。

 1:  using System;
 2:   
 3:  namespace DesignPatterns.Memento
 4:  {
 5:      /// <summary>
 6:      /// 书签接口(对外的窄接口)
 7:      /// </summary>
 8:      public interface IBookmark
 9:      { }
10:  }
11:   

2、阅读器类Reader,同时以私有内部类的形式实现具体的备忘录Bookmark(对内宽接口)。

 1:  using System;
 2:   
 3:  namespace DesignPatterns.Memento
 4:  {
 5:      /// <summary>
 6:      /// 阅读器
 7:      /// </summary>
 8:      public class Reader
 9:      {
10:          public Reader(string bookName, int pageNumber)
11:          {
12:              this.bookName = bookName;
13:              this.pageNumber = pageNumber;
14:          }
15:   
16:          //书名
17:          private string bookName;
18:   
19:          //页码
20:          private int pageNumber;
21:   
22:          //获得一个书签
23:          public IBookmark GetBookmark()
24:          {
25:              Console.WriteLine("建立书签:《" + this.bookName + "》第" + pageNumber + "页");
26:              return new Bookmark(this.bookName, this.pageNumber);
27:          }
28:   
29:          //从书签恢复
30:          public void Restore(IBookmark bookMark)
31:          {
32:              Bookmark bk = (Bookmark)bookMark;
33:              this.bookName = bk.BookName;
34:              this.pageNumber = bk.PageNumber;
35:              Console.WriteLine("恢复书签:《" + this.bookName + "》第" + pageNumber + "页");
36:          }
37:   
38:          //阅读
39:          public void Read()
40:          {
41:              Console.WriteLine("阅读:《" + this.bookName + "》第" + pageNumber + "页"); //阅读
42:              pageNumber++; //翻页
43:          }
44:   
45:          /// <summary>
46:          /// 书签实现(用内部类的方式实现对外的保密,或者说对内的宽接口)
47:          /// </summary>
48:          private class Bookmark : IBookmark
49:          {
50:              public Bookmark(string bookName, int pageNumber)
51:              {
52:                  this.BookName = bookName;
53:                  this.PageNumber = pageNumber;
54:              }
55:   
56:              /// <summary>
57:              /// 书名
58:              /// </summary>
59:              public string BookName { get; set; }
60:   
61:              /// <summary>
62:              /// 页码
63:              /// </summary>
64:              public int PageNumber { get; set; }
65:          }
66:      }
67:  }
68:   

3、书签管理器BookmarkCaretaker。

 1:  using System;
 2:  using System.Collections.Generic;
 3:   
 4:  namespace DesignPatterns.Memento
 5:  {
 6:      /// <summary>
 7:      /// 书签管理器
 8:      /// </summary>
 9:      public class BookmarkCaretaker
10:      {
11:          public BookmarkCaretaker()
12:          {
13:              this.bookmarks = new Dictionary<int, IBookmark>();
14:          }
15:   
16:          private Dictionary<int, IBookmark> bookmarks;
17:   
18:          public void AddBookmark(int key, IBookmark bookmark)
19:          {
20:              this.bookmarks.Add(key, bookmark);
21:          }
22:   
23:          public void RemoveBookmark(int key)
24:          {
25:              this.bookmarks.Remove(key);
26:          }
27:   
28:          public IBookmark GetBookmark(int key)
29:          {
30:              return bookmarks[key];
31:          }
32:      }
33:  }
34:   

4、测试客户端代码。

 1:  using System;
 2:   
 3:  namespace DesignPatterns.Memento
 4:  {
 5:      class Program
 6:      {
 7:          static void Main(string[] args)
 8:          {
 9:              BookmarkCaretaker caretaker = new BookmarkCaretaker();
10:              Reader reader = new Reader("设计模式", 1);
11:              reader.Read();
12:              reader.Read();
13:              reader.Read();
14:   
15:              caretaker.AddBookmark(1, reader.GetBookmark());
16:              reader.Read();
17:              reader.Read();
18:   
19:              caretaker.AddBookmark(2, reader.GetBookmark());
20:              reader.Read();
21:   
22:              reader.Restore(caretaker.GetBookmark(1));
23:              reader.Read();
24:   
25:              Console.WriteLine("按任意键结束...");
26:              Console.ReadKey();
27:          }
28:      }
29:  }
30:   

5、运行,查看结果。

image

posted @ 2012-09-14 10:59  宽厚  阅读(1689)  评论(1编辑  收藏  举报