O Memento é um padrão comportamental que permite capturar e armazenar o estado atual de um objeto de forma que ele possa ser restaurado posteriormente sem violar o encapsulamento. É particularmente útil para implementar funcionalidades de desfazer/refazer.
- Quando você precisa criar snapshots do estado de um objeto
- Quando você precisa implementar mecanismos de desfazer/refazer
- Quando você quer permitir que um objeto seja restaurado a um estado anterior
- Quando o acesso direto aos campos do objeto violaria seu encapsulamento
from __future__ import annotations
from typing import List, Optional
from datetime import datetime
import copy
# Memento - armazena o estado do editor
class DocumentoMemento:
def __init__(self, conteudo: str, selecao_inicio: int, selecao_fim: int):
self._conteudo = conteudo
self._selecao_inicio = selecao_inicio
self._selecao_fim = selecao_fim
self._data_criacao = datetime.now()
@property
def conteudo(self) -> str:
return self._conteudo
@property
def selecao_inicio(self) -> int:
return self._selecao_inicio
@property
def selecao_fim(self) -> int:
return self._selecao_fim
@property
def data_criacao(self) -> datetime:
return self._data_criacao
def __str__(self) -> str:
return (f"Snapshot [{self._data_criacao}] - "
f"Conteúdo: {self._conteudo}, "
f"Seleção: {self._selecao_inicio}-{self._selecao_fim}")
# Originador - o editor de texto em si
class EditorTexto:
def __init__(self):
self._conteudo = ""
self._selecao_inicio = 0
self._selecao_fim = 0
def escrever(self, texto: str) -> None:
# Remove o texto selecionado e insere o novo texto
antes = self._conteudo[:self._selecao_inicio]
depois = self._conteudo[self._selecao_fim:]
self._conteudo = antes + texto + depois
# Move o cursor para depois do texto inserido
self._selecao_inicio = self._selecao_fim = len(antes) + len(texto)
def selecionar(self, inicio: int, fim: int) -> None:
self._selecao_inicio = max(0, min(inicio, len(self._conteudo)))
self._selecao_fim = max(0, min(fim, len(self._conteudo)))
def get_conteudo(self) -> str:
return self._conteudo
def criar_memento(self) -> DocumentoMemento:
return DocumentoMemento(
self._conteudo,
self._selecao_inicio,
self._selecao_fim
)
def restaurar_de_memento(self, memento: DocumentoMemento) -> None:
self._conteudo = memento.conteudo
self._selecao_inicio = memento.selecao_inicio
self._selecao_fim = memento.selecao_fim
# Zelador - gerencia o histórico de estados
class HistoricoEditor:
def __init__(self, editor: EditorTexto):
self._editor = editor
self._historico: List[DocumentoMemento] = []
self._posicao_atual = -1
def backup(self) -> None:
# Remove estados futuros se estivermos no meio do histórico
if self._posicao_atual < len(self._historico) - 1:
self._historico = self._historico[:self._posicao_atual + 1]
self._historico.append(self._editor.criar_memento())
self._posicao_atual += 1
def desfazer(self) -> bool:
if self._posicao_atual <= 0:
return False
self._posicao_atual -= 1
memento = self._historico[self._posicao_atual]
self._editor.restaurar_de_memento(memento)
return True
def refazer(self) -> bool:
if self._posicao_atual >= len(self._historico) - 1:
return False
self._posicao_atual += 1
memento = self._historico[self._posicao_atual]
self._editor.restaurar_de_memento(memento)
return True
def mostrar_historico(self) -> None:
print("\nHistórico de alterações:")
for i, memento in enumerate(self._historico):
marcador = " ✓" if i == self._posicao_atual else ""
print(f"{i}: {memento}{marcador}")
def main():
# Criando o editor e seu histórico
editor = EditorTexto()
historico = HistoricoEditor(editor)
# Primeira alteração
editor.escrever("Olá ")
historico.backup()
print(f"Primeiro estado: {editor.get_conteudo()}")
# Segunda alteração
editor.escrever("mundo!")
historico.backup()
print(f"Segundo estado: {editor.get_conteudo()}")
# Terceira alteração
editor.selecionar(0, 4) # Seleciona "Olá "
editor.escrever("Hi")
historico.backup()
print(f"Terceiro estado: {editor.get_conteudo()}")
# Mostrando o histórico
historico.mostrar_historico()
# Desfazendo alterações
print("\nDesfazendo...")
historico.desfazer()
print(f"Após primeiro desfazer: {editor.get_conteudo()}")
historico.desfazer()
print(f"Após segundo desfazer: {editor.get_conteudo()}")
# Refazendo alterações
print("\nRefazendo...")
historico.refazer()
print(f"Após refazer: {editor.get_conteudo()}")
if __name__ == "__main__":
main()- Permite salvar e restaurar o estado de um objeto sem violar seu encapsulamento
- Simplifica a estrutura do originador
- Garante que o estado do objeto permaneça consistente
- Fornece uma maneira fácil de implementar funcionalidades de desfazer/refazer
- Permite criar snapshots imutáveis do estado do objeto
- Pode consumir muita memória se os clientes criarem mementos com frequência
- O zelador deve acompanhar o ciclo de vida do originador
- Pode ser complexo garantir que apenas o originador tenha acesso ao estado do memento
- Pode ser custoso em termos de performance para objetos que têm muito estado interno
- Use serialização para implementar mementos em casos onde o estado é muito grande
- Considere usar o padrão Command junto com Memento para operações desfazer/refazer
- Implemente estratégias de limpeza do histórico para evitar consumo excessivo de memória
- Considere usar compressão se os estados forem muito grandes
- Avalie se precisa armazenar apenas as diferenças entre estados em vez do estado completo
- Implemente mecanismos de proteção para garantir que apenas o originador possa acessar o estado do memento