C#
- Padrão Comportamental
Gof - Memento
![]() |
Neste artigo vou apresentar o padrão comportamental Gof Memento. |
Segundo a
definição da Gang Of Four(GoF), o padrão
Memento
tem a intenção de capturar e externalizar um estado interno de um objeto, sem
violar o encapsulamento, de modo que o mesmo possa posteriormente ser restaurado
para este estado.
A palavra
Memento
traduzida significa lembrança, recordação e esta relacionada com a lembrança de
eventos passados.
Ao usar este padrão, você pode restaurar um objeto ao seu estado anterior e
assim ele fornece uma maneira orientada a objetos de salvar o estado de um
objeto, ou seja, ele permite salvar e restaurar o estado de um objeto sem
quebrar as regras de encapsulamento definidas.
A criação de um ponto de restauração no Windows a partir do qual pode recuperar os dados se houver algum problema é um exemplo de como o padrão Memento atua. Outro exemplo seria o uso do CTRL+Z para restaurar um texto em um editor de texto.
Desta forma este padrão permite tirar um snapshot ou “retrato” do
estado de um objeto e a seguir restaurá-lo no futuro. Isso significa
que se você deseja realizar algum tipo de operação de desfazer ou rollback
em seu aplicativo, pode usar o padrão Memento para isso.
Uma forma muito usada na linguagem C# de aplicar o principio do padrão Memento é
usar a serialização.
Memento : Exemplo
Vejamos um exemplo
para entender melhor o padrão Memento.
Vamos supor que temos um objeto que representa uma instância de uma classe
Estudante. Este objeto possui os atributos Id,Nome, Idade, Curso, Nota e
Telefone , dentre outros com valores atribuídos.
Podemos dizer que esse é o estado atual do objeto ou seja o estado 1 :
Suponha que em um dado momento realizamos alterações nos valores das
propriedades Idade e Nota para esta instância do
objeto Estudante atribuindo novos valores a idade e
nota :
Assim podemos dizer que alteramos o estado do objeto que agora esta
representando pelo estado 2.
Se posteriormente precisarmos desfazer ou reverter as informações do estudante
para o estado anterior, ou seja, se precisarmos reverter do
estado 2 para o estado 1, podemos usar o padrão
Memento.
E como ele atua ?
Este padrão atua armazenando o estado original do objeto em um objeto externo
chamado Memento,e ,como esse objeto esta disponível
apenas para o objeto cujo estado armazenamos, o padrão respeita os princípios do
encapsulamento, e assim podemos restaurar o estado original do objeto.
É neste cenário que podemos usar é assim que atua o padrão Memento.
Diagrama UML
O diagrama UML do padrão Memento segundo o Gof apresenta os seguintes participantes :
1- Originator
- É o objeto a ser salvo ou armazenado;
- Cria um Memento contendo um snapshot do estado interno atual;
- Usa o Memento para restaurar este estado interno;
Esta classe possui
dois métodos :
a - CreateMemento - Cria uma instancia de Memento;
b - SetMemento - retorna o estado salvo e atribui o
valor ; este método aceita o objeto memento;
Esta classe instancia o objeto Memento e define o estado interno do Originator
para o estado memento, ou seja, ela tira um instantâneo do Originator e o coloca
no objeto memento. Este objeto memento será salvo no Caretaker para uso
posterior caso isso for preciso.
2- Memento
- Representa um
estado armazenado;
- Armazena o estado interno do objeto Originator;
Esta classe protege contra o estado do acesso de outros objetos que não o
Originator. Ela contém dois métodos :
a- SetState - usado para armazenar as informações
do estado;
b- GetState - usado para recuperar o estado salvo;
3- CareTaker
- Responsável por
persistir o Memento;
- Fornece o Memento de volta ao Originator para
restaurar o estado interno;
Esta classe apenas armazena o estado, ela nunca modifica ou examina o conteúdo
do objeto Memento. Aqui devemos tomar cuidado para não expor o estado do objeto
ao mundo exterior.
Quando podemos usar o padrão
Podemos usar o padrão Memento nos seguintes cenários :
- O estado de um
objeto precisa ser salvo e restaurado posteriormente (operações de desfazer ,
rollback, etc. );
- O estado de um objeto não pode ser exposto diretamente usando uma interface
sem expor a implementação;
Assim este padrão
é recomendado em qualquer aplicação em que o estado do objeto muda continuamente
e o usuário da aplicação pode decidir reverter ou desfazer as mudanças a
qualquer momento.
Vantagens do padrão
Como vantagens deste padrão temos que :
- Permite
armazenar o estado dos objetos sem comprometer o encapsulamento;
- Fornece um mecanismo de recuperação em caso de falhas;
- Fornece uma maneira de manter o histórico do ciclo de vida de um objeto;
Desvantagem
E como desvantagem podemos citar que :
O processo de salvar o estado de um objeto e restaurá-lo mais tarde pode levar algum tempo, ou seja, pode ser prejudicial ao desempenho do aplicativo.
A aplicação pode consumir uma grande quantidade de RAM se o usuário criar muitos pontos de restauração (Memento), e, o tempo extra para salvar os estados irá reduzir o desempenho geral do aplicativo.
Assim, dependendo da quantidade de informações de estado que deve ser armazenada dentro do objeto memento o processo de salvar e restaurar o estado pode impactar o desempenho. Além disso, a classe Caretaker vai precisar conter lógica adicional para ser capaz de gerenciar o Memento o que pode afetar a aplicação.
Exemplo de implementação do padrão Memento
Como exemplo de aplicação do padrão vamos implementar o padrão Memento para recuperar o estado de uma operação realizada com dois números inteiros.
Assim vamos poder realizar uma operação e ter um resultado:
Depois vamos realizar outra operação, e, a seguir vamos recuperar o resultado da
primeira operação :
Implementação prática
Levando em conta este cenário vamos implementar o padrão Memento usando uma aplicação Console .NET Core (.NET 5.0) criada no VS 2019 Community.
A seguir temos o diagrama de classes obtido a partir do VS 2019 na implementação do padrão:
Podemos identificar as seguinte classes :
-
ICalculadora - Define a interface para a
implementação do Originator;
-
Calculadora - Implementa a interface
ICalculadora e restaura o estado anterior.
Representa o Originator;
-
IOriginator - Permite o
Originator restaurar o seu estado;
- Memento -
Armazena o estado do objeto
Originator. Só temos Get não temos como
alterar os dados;
- ICareTake - Não definimos nenhuma operação nesta interface. (Poderíamos ter definido a data e o nome);
A seguir temos o código usado na implementação:
1- A interface ICalculadora
public interface ICalculadora { //CreateMemento ICaretaker BackupUltimoCalculo(); //SetMemento //servicos do Originator |
2- A Interface IOriginator
public interface IOriginator { int GetPrimeiroNumero(); int GetSegundoNumero(); } |
3- Classe Calculadora
public class Calculadora : ICalculadora { private int primeiroNumero; private int segundoNumero; //corresponde ao método CreateMemento() |
4- Classe Memento
public class Memento : ICaretaker, IOriginator
{
private int primeiroNumero;
private int segundoNumero;
public Memento(int numero1, int numero2)
{
primeiroNumero = numero1;
segundoNumero = numero2;
}
public int GetPrimeiroNumero()
{
return primeiroNumero;
}
public int GetSegundoNumero()
{
return segundoNumero;
}
}
|
7- Program
|
A execução do projeto irá apresentar o seguinte resultado:
Dessa forma o
padrão Memento nos dá uma maneira prática de armazenar e recuperar o estado de
um objeto. Você pode aproveitar esse padrão para realizar operações para
desfazer ou reverter o estado original.
Ao usar o padrão Memento, certifique-se de manter o desempenho em mente, tendo o
cuidado de não expor ao mundo externo a estrutura interna do seu objeto.
Este padrão esta relacionado com o padrão Command
que pode usar o Memento para manter o estado para
as operações que podem ser desfeitas.
Pegue o código
do projeto aqui :
Memento1.zip
"Ai dos que
ao mal chamam bem, e ao bem mal; que fazem das trevas luz, e da luz trevas;
e fazem do amargo doce, e do doce amargo!"
Isaías 5:20
Referências:
NET - Unit of Work - Padrão Unidade de ...
NET - O padrão de projeto Decorator
NET - Padrão de Projeto Builder
C# - O Padrão Strategy (revisitado)
NET - O padrão de projeto Command
NET - Apresentando o padrão Repository