Head First设计模式之备忘录模式

简介: 一、定义 不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态 二、结构   备忘录模式中主要有三类角色: 发起人角色:记录当前时刻的内部状态,负责创建和恢复备忘录数据。

一、定义

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

二、结构

  备忘录模式中主要有三类角色:

  • 发起人角色:记录当前时刻的内部状态,负责创建和恢复备忘录数据。
  • 备忘录角色:负责存储发起人对象的内部状态,在进行恢复时提供给发起人需要的状态。
  • 管理者角色:负责保存备忘录对象,但是不能对备忘录对象的内容进行操作或检查。

三、适用场景

1、需要保存/恢复数据的相关状态场景。

2、提供一个可回滚的操作。

四、优缺点

优点: 

1、给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。

2、实现了信息的封装,使得用户不需要关心状态的保存细节。

缺点:

消耗资源。

1、如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。

2、由于备份的信息是由发起人自己提供的,所以管理者无法预知备份的信息的大小,存在一定的未知风险。

 

五、实现

下面以备份手机通讯录为例子来实现了备忘录模式,具体的实现代码如下所示:

单次备份

// 联系人
    public class ContactPerson
    {
        public string Name { get; set; }
        public string MobileNum { get; set; }
    }

    // 发起人
    public class MobileOwner
    {
        // 发起人需要保存的内部状态
        public List<ContactPerson> ContactPersons { get; set; }

        public MobileOwner(List<ContactPerson> persons)
        {
            ContactPersons = persons;
        }

        // 创建备忘录,将当期要保存的联系人列表导入到备忘录中 
        public ContactMemento CreateMemento()
        {
            // 这里也应该传递深拷贝,new List方式传递的是浅拷贝,
            // 因为ContactPerson类中都是string类型,所以这里new list方式对ContactPerson对象执行了深拷贝
            // 如果ContactPerson包括非string的引用类型就会有问题,所以这里也应该用序列化传递深拷贝
            return new ContactMemento(new List<ContactPerson>(this.ContactPersons));
        }

        // 将备忘录中的数据备份导入到联系人列表中
        public void RestoreMemento(ContactMemento memento)
        {
            // 下面这种方式是错误的,因为这样传递的是引用,
            // 则删除一次可以恢复,但恢复之后再删除的话就恢复不了.
            // 所以应该传递contactPersonBack的深拷贝,深拷贝可以使用序列化来完成
            this.ContactPersons = memento.contactPersonBack;
        }

        public void Show()
        {
            Console.WriteLine("联系人列表中有{0}个人,他们是:", ContactPersons.Count);
            foreach (ContactPerson p in ContactPersons)
            {
                Console.WriteLine("姓名: {0} 号码为: {1}", p.Name, p.MobileNum);
            }
        }
    }

    // 备忘录
    public class ContactMemento
    {
        // 保存发起人的内部状态
        public List<ContactPerson> contactPersonBack;

        public ContactMemento(List<ContactPerson> persons)
        {
            contactPersonBack = persons;
        }
    }

    // 管理角色
    public class Caretaker
    {
        public ContactMemento ContactM { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<ContactPerson> persons = new List<ContactPerson>()
            {
                new ContactPerson() { Name= "Learning Hard", MobileNum = "123445"},
                new ContactPerson() { Name = "Tony", MobileNum = "234565"},
                new ContactPerson() { Name = "Jock", MobileNum = "231455"}
            };
            MobileOwner mobileOwner = new MobileOwner(persons);
            mobileOwner.Show();

            // 创建备忘录并保存备忘录对象
            Caretaker caretaker = new Caretaker();
            caretaker.ContactM = mobileOwner.CreateMemento();

            // 更改发起人联系人列表
            Console.WriteLine("----移除最后一个联系人--------");
            mobileOwner.ContactPersons.RemoveAt(2);
            mobileOwner.Show();

            // 恢复到原始状态
            Console.WriteLine("-------恢复联系人列表------");
            mobileOwner.RestoreMemento(caretaker.ContactM);
            mobileOwner.Show();

            Console.Read();
        }
    }

多次备份

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DesignPatterns.Mememto
{
    // 联系人
    public class ContactPerson
    {
        public string Name { get; set; }
        public string MobileNum { get; set; }
    }

    // 发起人
    public class MobileOwner
    {
        public List<ContactPerson> ContactPersons { get; set; }
        public MobileOwner(List<ContactPerson> persons)
        {
            ContactPersons = persons;
        }

        // 创建备忘录,将当期要保存的联系人列表导入到备忘录中 
        public ContactMemento CreateMemento()
        {
            // 这里也应该传递深拷贝,new List方式传递的是浅拷贝,
            // 因为ContactPerson类中都是string类型,所以这里new list方式对ContactPerson对象执行了深拷贝
            // 如果ContactPerson包括非string的引用类型就会有问题,所以这里也应该用序列化传递深拷贝
            return new ContactMemento(new List<ContactPerson>(this.ContactPersons));
        }

        // 将备忘录中的数据备份导入到联系人列表中
        public void RestoreMemento(ContactMemento memento)
        {
            if (memento != null)
            {
                // 下面这种方式是错误的,因为这样传递的是引用,
                // 则删除一次可以恢复,但恢复之后再删除的话就恢复不了.
                // 所以应该传递contactPersonBack的深拷贝,深拷贝可以使用序列化来完成
                this.ContactPersons = memento.ContactPersonBack;
            }
        }
        public void Show()
        {
            Console.WriteLine("联系人列表中有{0}个人,他们是:", ContactPersons.Count);
            foreach (ContactPerson p in ContactPersons)
            {
                Console.WriteLine("姓名: {0} 号码为: {1}", p.Name, p.MobileNum);
            }
        }
    }

    // 备忘录
    public class ContactMemento
    {
        public List<ContactPerson> ContactPersonBack { get; set; }
        public ContactMemento(List<ContactPerson> persons)
        {
            ContactPersonBack = persons;
        }
    }

    // 管理角色
    public class Caretaker
    {
        // 使用多个备忘录来存储多个备份点
        public Dictionary<string, ContactMemento> ContactMementoDic { get; set; }
        public Caretaker()
        {
            ContactMementoDic = new Dictionary<string, ContactMemento>();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<ContactPerson> persons = new List<ContactPerson>()
            {
                new ContactPerson() { Name= "Learning Hard", MobileNum = "123445"},
                new ContactPerson() { Name = "Tony", MobileNum = "234565"},
                new ContactPerson() { Name = "Jock", MobileNum = "231455"}
            };

            MobileOwner mobileOwner = new MobileOwner(persons);
            mobileOwner.Show();

            // 创建备忘录并保存备忘录对象
            Caretaker caretaker = new Caretaker();
            caretaker.ContactMementoDic.Add(DateTime.Now.ToString(), mobileOwner.CreateMemento());

            // 更改发起人联系人列表
            Console.WriteLine("----移除最后一个联系人--------");
            mobileOwner.ContactPersons.RemoveAt(2);
            mobileOwner.Show();

            // 创建第二个备份
            Thread.Sleep(1000);
            caretaker.ContactMementoDic.Add(DateTime.Now.ToString(), mobileOwner.CreateMemento());

            // 恢复到原始状态
            Console.WriteLine("-------恢复联系人列表,请从以下列表选择恢复的日期------");
            var keyCollection = caretaker.ContactMementoDic.Keys;
            foreach (string k in keyCollection)
            {
                Console.WriteLine("Key = {0}", k);
            }
            while (true)
            {
                Console.Write("请输入数字,按窗口的关闭键退出:");

                int index = -1;
                try
                {
                    index = Int32.Parse(Console.ReadLine());
                }
                catch
                {
                    Console.WriteLine("输入的格式错误");
                    continue;
                }

                ContactMemento contactMentor = null;
                if (index < keyCollection.Count && caretaker.ContactMementoDic.TryGetValue(keyCollection.ElementAt(index), out contactMentor))
                {
                    mobileOwner.RestoreMemento(contactMentor);
                    mobileOwner.Show();
                }
                else
                {
                    Console.WriteLine("输入的索引大于集合长度!");
                }
            }
        }
    }
}

 

 

参考

http://www.cnblogs.com/JsonShare/p/7283972.html

http://www.runoob.com/design-pattern/memento-pattern.html

http://www.cnblogs.com/zhili/p/MementoPattern.html

 


欢迎阅读本系列文章:Head First设计模式之目录 

 

相关文章
|
7月前
|
设计模式 存储 Java
23种设计模式,备忘录模式的概念优缺点以及JAVA代码举例
【4月更文挑战第9天】备忘录模式是一种行为设计模式,它能在不破坏对象封装的前提下,捕获并保存对象的当前状态,以便后面可以恢复到这个状态。
87 0
|
7月前
|
设计模式 存储 Java
【设计模式】备忘录模式
【设计模式】备忘录模式
|
7月前
|
设计模式 存储 Java
浅谈设计模式 - 备忘录模式(十五)
浅谈设计模式 - 备忘录模式(十五)
47 0
|
3月前
|
存储 设计模式 安全
Java设计模式-备忘录模式(23)
Java设计模式-备忘录模式(23)
|
4月前
|
设计模式 算法
设计模式的基础问题之备忘录模式在软件开发的问题如何解决
设计模式的基础问题之备忘录模式在软件开发的问题如何解决
|
5月前
|
设计模式 Java
Head First设计模式学习笔记
Head First设计模式学习笔记
|
6月前
|
设计模式
备忘录模式-大话设计模式
备忘录模式-大话设计模式
|
5月前
|
设计模式 数据处理
iLogtail设计模式问题之什么是备忘录模式
iLogtail设计模式问题之什么是备忘录模式
|
6月前
|
设计模式 存储 Java
Java设计模式之备忘录模式详解
Java设计模式之备忘录模式详解
|
7月前
|
存储 设计模式 安全
探索设计模式的魅力:备忘录模式揭秘-实现时光回溯、一键还原、后悔药、历史的守护者和穿越时空隧道
备忘录模式是一种行为设计模式,允许在不破坏对象封装性的情况下保存和恢复对象的内部状态。该模式通过创建备忘录对象来存储发起人的状态信息,发起人可根据需要创建和恢复备忘录。管理者则负责保存和管理备忘录,但无法访问其内容。备忘录模式简化了状态管理,支持撤销操作和历史记录功能,提高了系统的灵活性和可用性。在实际应用中,备忘录模式常用于文本编辑器、游戏和数据库事务处理等场景,确保对象状态的安全恢复和有效管理。通过备忘录模式,开发人员可以更好地控制对象状态的变化,提升软件系统的健壮性和用户体验。
155 1
探索设计模式的魅力:备忘录模式揭秘-实现时光回溯、一键还原、后悔药、历史的守护者和穿越时空隧道