Memento (informática)

Memento é um padrão de projeto de software documentado no Catálogo Gang of Four, sendo considerado como um padrão comportamental. Ele permite armazenar o estado interno de um objeto em um determinando momento, para que seja possível retorná-lo a este estado, sem que isso cause problemas com o encapsulamento.[1]

Ele funciona de maneira que uma classe é responsável por salvar o estado do objeto desejado enquanto que uma outra classe fica responsável por armazenar todas essas copias (mementos).

O padrão Memento é implementado se utilizando de três elementos: Originador, Armazenador e o Memento.

Motivação

editar

O Padrão Comportamental Memento possui uma grande gama de aplicações onde é necessário a recuperação de um estado anterior de um objeto como um todo, qualquer tipo de editor precisa oferecer uma maneira de desfazer ações como restaurar imagens, textos etc. Para isso, o padrão Memento procura recuperar o estado anterior dessas ações e copiar os mesmos para um objeto a ser restaurado.

Participantes

editar

Três objetos estão envolvidos na implementação do padrão Memento.

  • Originador
    • é o objeto cujo estado se deseja capturar.
  • Memento
    • responsável por armazenar o estado interno do objeto Originador.
  • Armazenador
    • é o objeto que acessará o originador, e deseja desfazer qualquer mudança efetuada, caso necessário.
    • ele é responsável por armazenar todos os Mementos.
    • os Mementos devem ser recuperados de maneira LIFO (Last In First Out) onde o ultimo adicionado será o primeiro a ser recuperado.

O Armazenador deve requisitar um objeto memento, antes de se valer do originador. Após efetuar as operações desejadas no originador, o cliente devolve a este o objeto memento, caso deseje desfazer qualquer alteração.

O objeto memento não permite o acesso de qualquer classe além da classe originador. Assim, tal padrão mostra-se útil por não violar o conceito de encapsulamento.

Funcionamento

editar

O objeto representado na classe Originador cria um novo memento a partir de si próprio, é ele que vai controlar toda a execução do Padrão Memento, criando uma nova instância da classe Armazenador, sempre que haja alguma modificação derivada de ações do sistema e de seu funcionamento padrão, o Originador irá criar um novo Memento, externalizando seu estado interno para um novo objeto que se tornará o Memento que será armazenado para posterior restauração. Além dos métodos e atributos próprios do objeto a ser restaurado, o Originador conta com um atributo que represente o estado atual do mesmo, métodos para definir e atribuir o estado, e métodos para salvar e solicitar o estado a partir do Memento.

Com o estado salvo no Objeto Memento, o Originador volta suas atenções para o Armazenador, quando o método que aciona a ação de modificação é invocado, o Memento é criado e adicionado no Armazenador, que, a partir de agora guardará os Mementos em uma pilha, usando o LIFO, para tanto, o Armazenador possui uma lista do tipo do Memento, possui métodos para adicionar um novo Memento e para acessar o ultimo adicionado na pilha do Armazenador, quando o ultimo for retirado, o topo da lista será o Memento com o estado anterior ao que foi solicitado, e assim por diante, até que não haja mais Mementos para serem acessados, nesse momento deve ser lançada uma exceção.

Contras

editar

O problema do Memento é que por ele sempre estar guardando o estado do objeto, ele pode guardar objetos demais e de maneira desnecessária e assim utilizando muito da memória da máquina.

Implementação

editar

O código em java a seguir ilustra a utilização do memento para desfazer ações de mudança de estado.

import java.util.List;
import java.util.ArrayList;
class Originator {
    private String state;
    public void setState(String state) {
        System.out.println("Originator: Mudando estado para " + state);
        this.state = state;
    }
    public Memento saveState() {
        System.out.println("Originator: Salvando o Memento.");
        return new Memento(this.state);
    }
    public void restoreState(Memento memento) {
        this.state = memento.getSavedState();
        System.out.println("Originator: Estado após restaurar o Memento: " + state);
    }
    public static class Memento {
        private final String state;
        public Memento(String stateToSave) {
            this.state = stateToSave;
        }
        private String getSavedState() {
            return this.state;
        }
    }
}
class Armazenador {
    public static void main(String[] args) {
        List<Originator.Memento> savedStates = new ArrayList<>();
        Originator originator = new Originator();
        originator.setState("Estado1");
        originator.setState("Estado2");
        savedStates.add(originador.saveState());
        originator.setState("Estado3");
        // Podemos ter múltiplos mementos e escolher qual queremos restaurar.
        savedStates.add(originator.saveState());
        originator.set("Estado4");
        originador.restoreState(savedStates.get(1));
    }
}

A saída deste código é:

Originador: Mudando estado para Estado1
Originador: Mudando estado para Estado2
Originador: Salvando o Memento.
Originador: Mudando estado para Estado3
Originador: Salvando o Memento.
Originador: Mudando estado para Estado4
Originador: Estado apos restaurar o Memento: Estado3

Este exemplo utiliza uma String como o estado, o que é um objeto imutável em Java. Em cenários da vida real, o estado na maioria das vezes é um objeto, neste caso uma copia do objeto deve ser feita.

  Este artigo sobre programação de computadores é um esboço. Você pode ajudar a Wikipédia expandindo-o.

Referências

editar
  1. Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994). Design Patterns: Elements of Reusable Object-Oriented Software. [S.l.]: Addison Wesley. pp. 283ff. ISBN 0-201-63361-2