Padrão de memento - Memento pattern
O padrão memento é um padrão de design de software que fornece a capacidade de restaurar um objeto ao seu estado anterior ( desfazer por meio de reversão).
O padrão memento é implementado com três objetos: o originador , um zelador e um memento . O originador é algum objeto que possui um estado interno. O zelador vai fazer algo para o originador, mas deseja desfazer a alteração. O zelador primeiro pede ao originador um objeto memento. Em seguida, ele faz qualquer operação (ou sequência de operações) que iria fazer. Para retornar ao estado anterior às operações, ele retorna o objeto memento ao originador. O próprio objeto memento é um objeto opaco (aquele que o zelador não pode, ou não deve, mudar). Ao usar esse padrão, deve-se tomar cuidado se o originador pode alterar outros objetos ou recursos - o padrão memento opera em um único objeto.
Exemplos clássicos do padrão memento incluem um gerador de número pseudo - aleatório (cada consumidor do PRNG serve como um zelador que pode inicializar o PRNG (o originador) com a mesma semente (o memento) para produzir uma sequência idêntica de números pseudo-aleatórios) e o estado em uma máquina de estados finitos .
Visão geral
O padrão de design Memento é um dos vinte e três padrões de design GoF bem conhecidos que descrevem como resolver problemas de design recorrentes para projetar software orientado a objetos flexível e reutilizável, ou seja, objetos que são mais fáceis de implementar, alterar, testar e reuso. O Memento Pattern foi criado por Noah Thompson, David Espiritu e Dr. Drew Clinkenbeard para os primeiros produtos HP.
Que problemas o padrão de design Memento pode resolver?
- O estado interno de um objeto deve ser salvo externamente para que o objeto possa ser restaurado a este estado posteriormente.
- O encapsulamento do objeto não deve ser violado.
O problema é que um objeto bem projetado é encapsulado de forma que sua representação (estrutura de dados) fica oculta dentro do objeto e não pode ser acessada de fora do objeto.
Que solução o padrão de design Memento descreve?
Tornar um objeto (originador) responsável por
- salvar seu estado interno para um objeto (memento) e
- restaurar a um estado anterior a partir de um objeto (memento).
Apenas o originador que criou um memento tem permissão para acessá-lo.
Um cliente (zelador) pode solicitar um memento do originador (para salvar o estado interno do originador) e passar um memento de volta para o originador (para restaurar a um estado anterior).
Isso permite salvar e restaurar o estado interno de um originador sem violar seu encapsulamento.
Consulte também a classe UML e o diagrama de sequência abaixo.
Estrutura
Classe UML e diagrama de sequência
No diagrama de classes UML acima , a Caretakerclasse se refere à Originatorclasse para salvar ( createMemento()) e restaurar ( restore(memento)) o estado interno do originador.
A Originatorclasse implementa
(1) createMemento()criando e retornando um Mementoobjeto que armazena o estado interno atual do originador e
(2) restore(memento)restaurando o estado do Mementoobjeto passado .
O diagrama de sequência UML
mostra as interações em tempo de execução:
(1) Salvando o estado interno do originador: O Caretakerobjeto chama createMemento()o Originatorobjeto, que cria um Mementoobjeto, salva seu estado interno atual ( setState()) e retorna o Mementopara o Caretaker.
(2) Restaurando o estado interno do originador: As Caretakerchamadas restore(memento)no Originatorobjeto e especifica o Mementoobjeto que armazena o estado que deve ser restaurado. O Originatorobtém o estado ( getState()) de Mementopara definir seu próprio estado.
Exemplo de Java
O programa Java a seguir ilustra o uso de "desfazer" do padrão memento.
import java.util.List;
import java.util.ArrayList;
class Originator {
private String state;
// The class could also contain additional data that is not part of the
// state saved in the memento..
public void set(String state) {
this.state = state;
System.out.println("Originator: Setting state to " + state);
}
public Memento saveToMemento() {
System.out.println("Originator: Saving to Memento.");
return new Memento(this.state);
}
public void restoreFromMemento(Memento memento) {
this.state = memento.getSavedState();
System.out.println("Originator: State after restoring from Memento: " + state);
}
public static class Memento {
private final String state;
public Memento(String stateToSave) {
state = stateToSave;
}
// accessible by outer class only
private String getSavedState() {
return state;
}
}
}
class Caretaker {
public static void main(String[] args) {
List<Originator.Memento> savedStates = new ArrayList<Originator.Memento>();
Originator originator = new Originator();
originator.set("State1");
originator.set("State2");
savedStates.add(originator.saveToMemento());
originator.set("State3");
// We can request multiple mementos, and choose which one to roll back to.
savedStates.add(originator.saveToMemento());
originator.set("State4");
originator.restoreFromMemento(savedStates.get(1));
}
}
O resultado é:
Originator: Setting state to State1 Originator: Setting state to State2 Originator: Saving to Memento. Originator: Setting state to State3 Originator: Saving to Memento. Originator: Setting state to State4 Originator: State after restoring from Memento: State3
Este exemplo usa uma String como o estado, que é um objeto imutável em Java. Em cenários da vida real, o estado quase sempre será um objeto mutável, caso em que uma cópia do estado deve ser feita.
Deve-se dizer que a implementação mostrada tem uma desvantagem: ela declara uma classe interna. Seria melhor se esta estratégia de memento pudesse se aplicar a mais de um originador.
Existem basicamente três outras maneiras de obter Memento:
- Serialização.
- Uma classe declarada no mesmo pacote.
- O objeto também pode ser acessado por meio de um proxy, que pode realizar qualquer operação de salvar / restaurar no objeto.
Exemplo C #
O padrão memento permite capturar o estado interno de um objeto sem violar o encapsulamento, de forma que mais tarde se possa desfazer / reverter as alterações, se necessário. Aqui, pode-se ver que o objeto memento é realmente usado para reverter as alterações feitas no objeto.
class Memento
{
private readonly string savedState;
private Memento(string stateToSave)
{
savedState = stateToSave;
}
public class Originator
{
private string state;
// The class could also contain additional data that is not part of the
// state saved in the memento.
public void Set(string state)
{
Console.WriteLine("Originator: Setting state to " + state);
this.state = state;
}
public Memento SaveToMemento()
{
Console.WriteLine("Originator: Saving to Memento.");
return new Memento(state);
}
public void RestoreFromMemento(Memento memento)
{
state = memento.savedState;
Console.WriteLine("Originator: State after restoring from Memento: " + state);
}
}
}
class Caretaker
{
static void Main(string[] args)
{
List<Memento> savedStates = new List<Memento>();
Memento.Originator originator = new Memento.Originator();
originator.Set("State1");
originator.Set("State2");
savedStates.Add(originator.SaveToMemento());
originator.Set("State3");
// We can request multiple mementos, and choose which one to roll back to.
savedStates.Add(originator.SaveToMemento());
originator.Set("State4");
originator.RestoreFromMemento(savedStates[1]);
}
}
Exemplo Python
"""
Memento pattern example.
"""
class Memento:
def __init__(self, state) -> None:
self._state = state
def get_saved_state(self):
return self._state
class Originator:
_state = ""
def set(self, state) -> None:
print("Originator: Setting state to", state)
self._state = state
def save_to_memento(self) -> Memento:
print("Originator: Saving to Memento.")
return Memento(self._state)
def restore_from_memento(self, memento) -> None:
self._state = memento.get_saved_state()
print("Originator: State after restoring from Memento:", self._state)
saved_states = []
originator = Originator()
originator.set("State1")
originator.set("State2")
saved_states.append(originator.save_to_memento())
originator.set("State3")
saved_states.append(originator.save_to_memento())
originator.set("State4")
originator.restore_from_memento(saved_states[1])
Referências
links externos
- Descrição do padrão Memento em Ada
- Memento UML Class Diagram com amostras de código C # e .NET
- Tutorial do SourceMaking
- Memento Design Pattern usando Java
