Хранитель (шаблон проектирования)
Хранитель | |
---|---|
Memento | |
Тип | поведенческий |
Описан в Design Patterns | Да |
Хранитель (также известный как Memento, Token, Лексема) — поведенческий шаблон проектирования.
Позволяет не нарушая инкапсуляцию зафиксировать и сохранить внутреннее состояния объекта так, чтобы позднее восстановить его в этом состоянии.
Применение
Шаблон Хранитель используется, когда:
- необходимо сохранить снимок состояния объекта (или его части) для последующего восстановления
- прямой интерфейс получения состояния объекта раскрывает детали реализации и нарушает инкапсуляцию объекта
Структура
- Originator - "Создатель"
- Caretaker - "Опекун"
- Memento - "Хранитель"
Описание
Шаблон Хранитель используется двумя объектами: "Создателем" (originator) и "Опекуном" (caretaker). "Создатель" - это объект, у которого есть внутреннее состояние. Объект "Опекун" может производить некоторые действия с "Создателем", но при этом необходимо иметь возможность восстановить изменения. Для этого "Опекун" запрашивает у "Создателя" объект "Хранителя". Затем выполняет запланированное действие (или последовательность действий). Для выполнения отката "Создателя" к состоянию, которое предшествовало изменениям, "Опекун" возвращает объект "Хранителя" его "Создателю". "Хранитель" является непрозрачным (т.е. таким, который не может или не должен изменяться "Опекуном").
Примеры реализации
//This structural code demonstrates the Memento pattern which temporary saves and restores another object's internal state.
// Memento pattern -- Structural example
using System;
namespace DoFactory.GangOfFour.Memento.Structural
{
/// <summary>
/// MainApp startup class for Structural
/// Memento Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
Originator o = new Originator();
o.State = "On";
// Store internal state
Caretaker c = new Caretaker();
c.Memento = o.CreateMemento();
// Continue changing originator
o.State = "Off";
// Restore saved state
o.SetMemento(c.Memento);
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Originator' class
/// </summary>
class Originator
{
private string _state;
// Property
public string State
{
get { return _state; }
set
{
_state = value;
Console.WriteLine("State = " + _state);
}
}
// Creates memento
public Memento CreateMemento()
{
return (new Memento(_state));
}
// Restores original state
public void SetMemento(Memento memento)
{
Console.WriteLine("Restoring state...");
State = memento.State;
}
}
/// <summary>
/// The 'Memento' class
/// </summary>
class Memento
{
private string _state;
// Constructor
public Memento(string state)
{
this._state = state;
}
// Gets or sets state
public string State
{
get { return _state; }
}
}
/// <summary>
/// The 'Caretaker' class
/// </summary>
class Caretaker
{
private Memento _memento;
// Gets or sets memento
public Memento Memento
{
set { _memento = value; }
get { return _memento; }
}
}
}
Output
State = On
State = Off
Restoring state:
State = On
C#
using System;
namespace MementoPattern
{
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo("Test", 15);
foo.Print();
Caretaker ct1 = new Caretaker();
Caretaker ct2 = new Caretaker();
ct1.SaveState(foo);
foo.IntProperty += 152;
foo.Print();
ct2.SaveState(foo);
ct1.RestoreState(foo);
foo.Print();
ct2.RestoreState(foo);
foo.Print();
Console.ReadKey();
}
}
public interface IOriginator
{
object GetMemento();
void SetMemento(object memento);
}
public class Foo
: IOriginator
{
public string StringProperty
{
get;
private set;
}
public int IntProperty
{
get;
set;
}
public Foo(string stringPropertyValue, int intPropertyValue = 0)
{
StringProperty = stringPropertyValue;
IntProperty = intPropertyValue;
}
public void Print()
{
Console.WriteLine("=============");
Console.WriteLine("StringProperty value: {0}",StringProperty);
Console.WriteLine("IntProperty value: {0}",IntProperty);
Console.WriteLine("=============");
}
object IOriginator.GetMemento()
{
return new Memento { StringProperty = this.StringProperty, IntProperty = this.IntProperty };
}
void IOriginator.SetMemento(object memento)
{
if (Object.ReferenceEquals(memento, null))
throw new ArgumentNullException("memento");
if (!(memento is Memento))
throw new ArgumentException("memento");
StringProperty = ((Memento)memento).StringProperty;
IntProperty = ((Memento)memento).IntProperty;
}
class Memento
{
public string StringProperty
{
get;
set;
}
public int IntProperty
{
get;
set;
}
}
}
public class Caretaker
{
private object m_memento;
public void SaveState(IOriginator originator)
{
if (originator == null)
throw new ArgumentNullException("originator");
m_memento = originator.GetMemento();
}
public void RestoreState(IOriginator originator)
{
if (originator == null)
throw new ArgumentNullException("originator");
if (m_memento == null)
throw new InvalidOperationException("m_memento == null");
originator.SetMemento(m_memento);
}
}
}