[sw design pattern] Memento (Lembrança)
Os padrões de design GoF são classificados em três categorias: Criacionais, Comportamentais e Estruturais. Os padrões criacionais tratam da criação de objetos, enquanto os padrões estruturais lidam com a estrutura das classes, como herança e composição. Por fim, os padrões comportamentais lidam com a comunicação entre objetos e suas interações. Estes padrões de projeto se encontram no livro “Padrões de Projetos: Soluções Reutilizáveis de Software Orientado a Objetos” escrito por 4 autores denominados GoF (Gang of Four).
O padrão Memento é um padrão de design comportamental que permite capturar e armazenar o estado interno de um objeto sem violar o encapsulamento. Isso permite que o objeto seja restaurado para um estado anterior, se necessário. O padrão é composto por três partes principais: o Originador, o Memento e o Zelador.
O Originador é o objeto que possui o estado interno que precisa ser salvo. Ele cria um Memento que contém uma cópia do estado interno atual e o passa para o Zelador para armazenamento.
O Memento é uma classe que contém uma cópia do estado interno do Originador. O Zelador é responsável por armazenar e gerenciar os Mementos. Aqui está um exemplo em Java que demonstra o padrão Memento:
public class Originador {
private String estado;
public void setEstado(String estado) {
this.estado = estado;
}
public Memento salvarEstado() {
return new Memento(estado);
}
public void restaurarEstado(Memento memento) {
estado = memento.getEstadoSalvo();
}
}
public class Memento {
private String estadoSalvo;
public Memento(String estado) {
estadoSalvo = estado;
}
public String getEstadoSalvo() {
return estadoSalvo;
}
}
public class Zelador {
private Memento memento;
public void setMemento(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
}
public class Exemplo {
public static void main(String[] args) {
Originador originador = new Originador();
Zelador zelador = new Zelador();
originador.setEstado("Estado 1");
originador.setEstado("Estado 2");
zelador.setMemento(originador.salvarEstado());
originador.setEstado("Estado 3");
zelador.setMemento(originador.salvarEstado());
originador.setEstado("Estado 4");
System.out.println("Estado atual: " + originador.getEstado());
originador.restaurarEstado(zelador.getMemento());
System.out.println("Estado restaurado: " + originador.getEstado());
}
}
Neste exemplo, o Originador é representado pela classe Originador
, que possui um estado interno representado pela variável estado
. O método setEstado
é usado para atualizar o estado interno do objeto. O método salvarEstado
cria um novo objeto Memento
que contém uma cópia do estado interno atual do Originador
.
A classe Memento
representa o objeto Memento, que contém uma cópia do estado interno do Originador. O método getEstadoSalvo
é usado para obter o estado interno salvo.
A classe Zelador
é responsável por armazenar e gerenciar os objetos Memento. O método setMemento
é usado para armazenar um novo objeto Memento
e o método getMemento
é usado para obter o objeto Memento
mais recente.
No método main
, um novo objeto Originador
e Zelador
são criados. O estado interno do Originador
é atualizado várias vezes e um novo objeto Memento
é criado e armazenado no Zelador
após cada atualização. O estado interno do Originador
é então restaurado para um estado anterior usando o objeto Memento
mais recente armazenado no Zelador
.
Em resumo, o padrão Memento
permite que o estado interno de um objeto seja salvo e restaurado sem violar o encapsulamento. Isso é útil em situações em que é necessário desfazer uma série de alterações em um objeto. O resultado do código de exemplo será:
Estado atual: Estado 4
Estado restaurado: Estado 3
Isso ocorre porque o estado do objeto Originador é atualizado várias vezes e um novo objeto Memento é criado e armazenado no objeto Zelador após cada atualização. O estado do objeto Originador é então restaurado para um estado anterior usando o objeto Memento mais recente armazenado no objeto Zelador.
Neste caso, o estado do objeto Originador é atualizado para "Estado 1", depois para "Estado 2", em seguida, um objeto Memento é criado e armazenado no objeto Zelador. O estado do objeto Originador é então atualizado para "Estado 3", outro objeto Memento é criado e armazenado no objeto Zelador, e finalmente o estado do objeto Originador é atualizado para "Estado 4".
Quando o estado do objeto Originador é restaurado para um estado anterior usando o objeto Memento mais recente armazenado no objeto Zelador, o estado do objeto Originador é restaurado para "Estado 3". Isso ocorre porque o objeto Memento mais recente armazenado no objeto Zelador foi criado quando o estado do objeto Originador era "Estado 3".
Algumas possíveis relações do padrão Memento com outros padrões de projeto são:
- Padrão Command: O padrão Command pode ser usado em conjunto com o padrão Memento para implementar desfazer/ refazer. O objeto Command pode armazenar um objeto Memento que representa o estado anterior do objeto receptor antes de executar uma operação. Se a operação precisar ser desfeita, o objeto Command pode restaurar o estado anterior do objeto receptor a partir do objeto Memento.
- Padrão State: O padrão State pode ser usado em conjunto com o padrão Memento para implementar transições de estado. O objeto Memento pode armazenar o estado anterior do objeto receptor, que pode ser restaurado se a transição de estado falhar ou precisar ser desfeita.
- Padrão Iterator: O padrão Iterator pode ser usado em conjunto com o padrão Memento para percorrer uma lista de objetos Memento. Isso pode ser útil se você precisar implementar desfazer/ refazer em uma lista de objetos.
- Padrão Composite: O padrão Composite pode ser usado em conjunto com o padrão Memento para capturar e restaurar o estado de um objeto composto. O objeto Memento pode armazenar o estado de todos os objetos filhos do objeto composto, permitindo que você restaure o estado completo do objeto composto.
Aqui está um exemplo de código em Java que demonstra o padrão Memento em conjunto com o padrão Command:
javaCopy// Classe Memento
public class EditorMemento {
private final String conteudo;
public EditorMemento(String conteudo) {
this.conteudo = conteudo;
}
public String getConteudo() {
return conteudo;
}
}
// Classe Editor
public class Editor {
private String conteudo;
public void escrever(String conteudo) {
this.conteudo = conteudo;
}
public EditorMemento salvar() {
return new EditorMemento(conteudo);
}
public void restaurar(EditorMemento memento) {
conteudo = memento.getConteudo();
}
}
// Classe Command
public interface Comando {
void executar();
void desfazer();
}
// Classe ComandoEscrever
public class ComandoEscrever implements Comando {
private final Editor editor;
private final String conteudoAnterior;
public ComandoEscrever(Editor editor) {
this.editor = editor;
this.conteudoAnterior = editor.getConteudo();
}
@Override
public void executar() {
editor.escrever("Novo conteúdo");
}
@Override
public void desfazer() {
editor.restaurar(new EditorMemento(conteudoAnterior));
}
}
// Classe Cliente
public class Cliente {
public static void main(String[] args) {
Editor editor = new Editor();
Comando comando = new ComandoEscrever(editor);
// Escreve novo conteúdo
comando.executar();
// Salva o estado atual do editor
EditorMemento memento = editor.salvar();
// Escreve outro conteúdo
comando.executar();
// Desfaz a última operação
comando.desfazer();
// Restaura o estado anterior do editor
editor.restaurar(memento);
}
}
Aqui está uma explicação do código acima:
- Classe Memento: A classe EditorMemento é uma classe que representa um objeto Memento. Ela tem um atributo conteudo que armazena o estado interno do objeto Editor em um determinado momento no tempo. A classe tem um construtor que recebe o conteúdo do editor e um método getConteudo() que retorna o conteúdo armazenado.
- Classe Editor: A classe Editor é uma classe que representa o objeto que deseja salvar e restaurar seu estado interno. Ela tem um método escrever() que permite que você escreva um novo conteúdo no editor, um método salvar() que cria um objeto Memento contendo o estado atual do editor e um método restaurar() que restaura o estado do editor a partir de um objeto Memento.
- Classe Command: A interface Comando é uma interface que define a interface para um objeto Command. Ela tem dois métodos: executar() e desfazer(). O método executar() é usado para executar a solicitação encapsulada pelo objeto Command, e o método desfazer() é usado para desfazer a solicitação.
- Classe ComandoEscrever: A classe ComandoEscrever é uma classe que implementa a interface Comando. Ela encapsula a solicitação de escrever um novo conteúdo no editor. Ela tem um construtor que recebe um objeto Editor e armazena o conteúdo anterior do editor em uma variável. O método executar() escreve um novo conteúdo no editor, e o método desfazer() restaura o conteúdo anterior do editor a partir do objeto Memento.
- Classe Cliente: A classe Cliente é uma classe que contém o método main(). Ela cria um objeto Editor e um objeto ComandoEscrever. Ela executa o método executar() do objeto ComandoEscrever para escrever um novo conteúdo no editor e, em seguida, salva o estado atual do editor em um objeto Memento. Em seguida, ela executa o método executar() novamente para escrever outro conteúdo no editor. Em seguida, ela executa o método desfazer() do objeto ComandoEscrever para desfazer a última operação e, finalmente, restaura o estado anterior do editor a partir do objeto Memento.
links externos com mais exemplos do padrão Memento:
—> O código do link abaixo é um exemplo de implementação do padrão de projeto Memento em Java. Ele consiste em três classes principais: TextEditor
, TextWindow
e TextWindowState
.
- Classe TextEditor: A classe
TextEditor
é uma classe que representa o objeto que deseja salvar e restaurar seu estado interno. Ela tem um atributotextWindow
que é uma instância da classeTextWindow
. - Classe TextWindow: A classe
TextWindow
é uma classe que representa o estado interno do objetoTextEditor
. Ela tem um atributocurrentText
que é um objetoStringBuilder
que armazena o texto atual. - Classe TextWindowState: A classe
TextWindowState
é uma classe que representa um objeto Memento. Ela tem um atributotext
que armazena o estado interno do objetoTextWindow
em um determinado momento no tempo. A classe tem um construtor que recebe o texto atual doTextWindow
e um métodogetText()
que retorna o texto armazenado. - Métodos save() e restore(): A classe
TextWindow
tem dois métodos:save()
erestore()
. O métodosave()
cria um objetoTextWindowState
contendo o estado atual doTextWindow
. O métodorestore()
restaura o estado doTextWindow
a partir de um objetoTextWindowState
. - Métodos hitSave() e hitUndo(): A classe
TextEditor
tem dois métodos:hitSave()
ehitUndo()
. O métodohitSave()
chama o métodosave()
do objetoTextWindow
para salvar o estado atual em um objetoTextWindowState
. O métodohitUndo()
chama o métodorestore()
do objetoTextWindow
para restaurar o estado anterior a partir do objetoTextWindowState
salvo. - Método write(): A classe
TextEditor
tem um métodowrite()
que permite escrever um novo texto noTextWindow
. - Método print(): A classe
TextEditor
tem um métodoprint()
que retorna o texto atual doTextWindow
.
O exemplo cria um objeto TextEditor
e escreve duas linhas de texto no TextWindow
. Em seguida, ele chama o método hitSave()
para salvar o estado atual do TextWindow
. Em seguida, ele escreve outra linha de texto no TextWindow
. Em seguida, ele chama o método hitUndo()
para desfazer a última operação e restaurar o estado anterior do TextWindow
. Finalmente, ele verifica se o texto atual do TextWindow
é igual ao texto original.
https://www.baeldung.com/java-memento-design-pattern
O código do blog abaixo é um exemplo do padrão de design Memento em Java. Ele consiste em quatro classes: Employee
, EmployeeMemento
, EmployeeCaretaker
e Main
.
- Classe Employee: A classe
Employee
representa um objeto de funcionário com atributos comoempId
,name
,designation
,salary
,department
eproject
. Ela tem métodos para obter e definir esses atributos, bem como métodos para criar e restaurar mementos. - Classe EmployeeMemento: A classe
EmployeeMemento
representa um objeto de memento que armazena o estado de um objetoEmployee
. Ela tem atributos para cada um dos atributos deEmployee
e um construtor para criar um novo memento. - Classe EmployeeCaretaker: A classe
EmployeeCaretaker
é responsável por armazenar e recuperar mementos para objetosEmployee
. Ela usa um mapa para armazenar mementos para cada funcionário e fornece métodos para adicionar e recuperar mementos. - Classe Main: A classe
Main
é o ponto de entrada do programa. Ela cria dois objetosEmployee
, define seus atributos, cria mementos e os adiciona aoEmployeeCaretaker
. Em seguida, modifica os objetosEmployee
, cria novos mementos e os adiciona aoEmployeeCaretaker
. Finalmente, recupera mementos doEmployeeCaretaker
e restaura os objetosEmployee
para seus estados anteriores.
O exemplo demonstra como usar o padrão de design Memento para salvar e restaurar o estado de um objeto. Ele usa a classe Employee
para representar um objeto com estado, a classe EmployeeMemento
para armazenar o estado e a classe EmployeeCaretaker
para gerenciar os mementos. A classe Main
mostra como criar, modificar e restaurar objetos Employee
usando mementos.
https://dzone.com/articles/memento-design-pattern-in-java
REFERÊNCIAS:
- Memento Design Pattern - GeeksforGeeks: https://www.geeksforgeeks.org/memento-design-pattern/
- Memento Design Pattern - Tutorialspoint: https://www.tutorialspoint.com/design_pattern/memento_pattern.htm
- Memento Design Pattern - Refactoring Guru: https://refactoring.guru/design-patterns/memento
- Memento Design Pattern - SourceMaking: https://sourcemaking.com/design_patterns/memento
- Memento Design Pattern - Wikipedia: https://en.wikipedia.org/wiki/Memento_pattern
- Memento Design Pattern and Its Uses - DZone: https://dzone.com/articles/memento-design-pattern-and-its-uses
- Memento Design Pattern - Relationship with Other Patterns - Javatpoint: https://www.javatpoint.com/memento-design-pattern-relationship-with-other-patterns
- Memento Design Pattern - Relationship with Other Patterns - Refactoring Guru: https://refactoring.guru/design-patterns/memento/related-patterns