Memento Design Pattern em Java
1. Visão geral
Neste tutorial, aprenderemos o que é o Memento Design Pattern e como usá-lo.
Primeiro, vamos passar um pouco de teoria. Então, criaremos um exemplo onde ilustraremos o uso do padrão.
2. Qual é o padrão de design do Memento?
O Memento Design Pattern, descrito porGang of Four in their book, é um padrão de design comportamental. The Memento Design Pattern offers a solution to implement undoable actions. Podemos fazer isso salvando o estado de um objeto em um determinado instante e restaurando-o se as ações executadas desde então precisarem ser desfeitas.
Praticamente, o objeto cujo estado precisa ser salvo é chamado de Originador. O zelador é o objeto que aciona o salvamento e a restauração do estado, chamado de Memento.
O objeto Memento deve expor o mínimo de informações possível ao zelador. Isso é para garantir que não exponhamos o estado interno do Originador para o mundo externo, pois isso quebraria os princípios de encapsulamento. No entanto, o Originador deve acessar informações suficientes para restaurar o estado original.
Vamos ver um diagrama de classe rápido ilustrando como os diferentes objetos interagem entre si:
Como podemos ver, o Originador pode produzir e consumir um Memento. Enquanto isso, o zelador apenas mantém o estado antes de restaurá-lo. A representação interna do Originador é mantida oculta do mundo externo.
Aqui, usamos um único campo para representar o estado do Originador, emborawe’re not limited to one field and could have used as many fields as necessary. Além disso, o estado mantido no objeto Memento não precisa corresponder ao estado completo do Originador. Contanto que as informações mantidas sejam suficientes para restaurar o estado do Originador, estamos prontos para prosseguir.
3. Quando usar o Memento Design Pattern?
Normalmente, o Memento Design Pattern será usado em situações em que algumas ações são desfeitos, exigindo, portanto, a reversão para um estado anterior. However, if the state of the Originator is heavy, using the Memento Design Pattern can lead to an expensive creation process and increased use of memory.
4. Exemplo do Padrão Memento
4.1. Amostra inicial
Vamos agora ver um exemplo do Memento Design Pattern. Vamos imaginar que temos um editor de texto:
public class TextEditor {
private TextWindow textWindow;
public TextEditor(TextWindow textWindow) {
this.textWindow = textWindow;
}
}
Possui uma janela de texto, que contém o texto inserido no momento, e fornece uma maneira de adicionar mais texto:
public class TextWindow {
private StringBuilder currentText;
public TextWindow() {
this.currentText = new StringBuilder();
}
public void addText(String text) {
currentText.append(text);
}
}
4.2. Lembrança
Agora, vamos imaginar que queremos que nosso editor de texto implemente alguns recursos de salvar e desfazer. When saving, we want our current text to be saved. Thus, when undoing subsequent changes, we’ll have our saved text restored.
Para fazer isso, usaremos o Memento Design Pattern. Primeiro, vamos criar um objeto que contém o texto atual da janela:
public class TextWindowState {
private String text;
public TextWindowState(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
Este objeto é a nossa lembrança. Como podemos ver, escolhemos usarString em vez deStringBuilder para evitar qualquer atualização do texto atual por estranhos.
4.3. Originador
Depois disso, teremos que fornecer à classeTextWindow métodos para criar e consumir o objeto Memento, tornando oTextWindow nosso Originador:
public TextWindowState save() {
return new TextWindowState(wholeText.toString());
}
public void restore(TextWindowState save) {
currentText = new StringBuilder(save.getText());
}
O métodosave() nos permite criar o objeto, enquanto o métodorestore() o consome para restaurar o estado anterior.
4.4. Zelador
Finalmente, temos que atualizar nossa classeTextEditor. As the Caretaker, it will hold the state of the Originator and ask to restore it when needed:
private TextWindowState savedTextWindow;
public void hitSave() {
savedTextWindow = textWindow.save();
}
public void hitUndo() {
textWindow.restore(savedTextWindow);
}
4.5. Testando a solução
Vamos ver se funciona por meio de uma execução de amostra. Imagine que adicionamos algum texto ao nosso editor, salve-o e depois adicione um pouco mais e, finalmente, desfaça. Para conseguir isso, vamos adicionar um métodoprint() em nossoTextEditor que retorna umString do texto atual:
TextEditor textEditor = new TextEditor(new TextWindow());
textEditor.write("The Memento Design Pattern\n");
textEditor.write("How to implement it in Java?\n");
textEditor.hitSave();
textEditor.write("Buy milk and eggs before coming home\n");
textEditor.hitUndo();
assertThat(textEditor.print()).isEqualTo("The Memento Design Pattern\nHow to implement it in Java?\n");
Como podemos ver, a última frase não faz parte do texto atual, pois o Memento foi salvo antes de adicioná-lo.
5. Conclusão
Neste breve artigo, explicamos o Memento Design Pattern e para que ele pode ser usado. Também examinamos um exemplo que ilustra seu uso em um editor de texto simples.
O código completo usado neste artigo pode ser encontradoover on GitHub.