備忘錄模式

概述

先從面向對象的三大特徵之一封裝說起。面向對象的封裝簡單點說就是把狀態(數據)和行爲(操作這些數據的方法)放到一起,構成一個單元,通常叫做類。一個對象的行爲是事先確定好的(靜態)一些腳本,如果對象的狀態相同,對象看起來就是一樣的。所以當我們需要把一個對象的某一時刻保存起來,那麼只需要保存它在那個時刻的狀態;相反需要恢復對象到某一時刻時,只需恢復它在那個時刻的狀態。這就是備忘錄模式的原理。

在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態。這樣以後就可將該對象恢復到原先保存的狀態。

上面是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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章