Padrão de Projeto Memento Kleinner Farias e Raphael do Vale © LES/PUC-Rio Agenda • Intenção • Motivação • Aplicabilidade • Estrutura • Participantes • Conseqüências • Implementação • Exemplo © LES/PUC-Rio Intenção • Sem violar o encapsulamento, capturar e externalizar um estado interno de um objeto, de maneira que o objeto possa ser restaurando para este estado mais tarde. © LES/PUC-Rio Motivação • Algumas vezes é necessário registrar o estado interno de um objeto. • Implementação de mecanismos de checkpoints e de desfazer que permitem aos usuários retroceder de operações ou recuperar-se de erros. • Trata-se de um objeto que armazena uma “instância” do estado interno de um objeto. © LES/PUC-Rio Aplicabilidade • Usado quando o estado de um objeto deve ser salvo de maneira que possa ser restaurado mais adiante. • O uso de interface para o obtenção do estado de um objeto expõe detalhes da implementação que rompe o princípio de encapsulamento de OO. © LES/PUC-Rio Estrutura © LES/PUC-Rio Participantes • Memento – Armazena o estado interno do objeto; – Protege contra acesso por objetos que não o originador. • Originador – Cria um memento contendo uma “instância” do estado interno corrente; – Usa o memento para restaurar o seu estado interno; • Caretaker – É responsável pela custódia do memento; – Nunca opera ou examina os conteúdos de um memento. © LES/PUC-Rio Conseqüências • Preservação das fronteiras de encapsulamento – O padrão evita a exposição de informação que somente um originador deveria administrar. • Ele simplifica o originador – Coloca a carga de administração do armazenamento fora do Originador. • O uso de mementos pode ser computacionalmente caro – Se o Originador tiver que copiar grandes quantidades de informação para armazenar no memento. Ou se os clientes criam e devolvem mementos para o Originador com freqüência. © LES/PUC-Rio Implementação class Originator { class Caretaker { private String state; private List savedStates = new ArrayList(); public void set(String state) { this.state = state; public void addMemento(Object m) { } savedStates.add(m); public Object saveToMemento() { } return new Memento(state); public Object getMemento(int index) { } return savedStates.get(index); public void restoreFromMemento(Object m) { } if (m instanceof } Memento) { Memento memento = (Memento)m; state = memento.getSavedState(); } } private static class Memento { private String state; public Memento(String stateToSave) { state = stateToSave; } public String getSavedState() { return state; } } } © LES/PUC-Rio Implementação • Armazenando mudanças incrementais – Quando mementos são criados e passados de volta para o seu originador, em uma seqüência previsível, um Memento pode salvar somente a mudança incremental do estado interno do originador. • Proteção dos dados – É importante impor métodos de proteger os dados do memento. Somente o originador pode modificar ou obter os dados internos de um memento. © LES/PUC-Rio Exemplo • Controle de alterações de registros importantes – Utilizando o padrão Memento, é possível guardar versões de registros importantes a cada modificação. – Para cada usuário que modificar o registro, podemos armazenar em uma espécie de log o memento do registro e o usuário que o alterou. Assim é possível ter uma auditoria, verificando todas alterações feitas pelos usuários e permitindo “voltar atrás”. © LES/PUC-Rio