Skip to content

Latest commit

 

History

History
186 lines (146 loc) · 6.29 KB

File metadata and controls

186 lines (146 loc) · 6.29 KB

Memento

O que é?

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 usar?

  • 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

Exemplo em Python

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()

Vantagens

  1. Permite salvar e restaurar o estado de um objeto sem violar seu encapsulamento
  2. Simplifica a estrutura do originador
  3. Garante que o estado do objeto permaneça consistente
  4. Fornece uma maneira fácil de implementar funcionalidades de desfazer/refazer
  5. Permite criar snapshots imutáveis do estado do objeto

Desvantagens

  1. Pode consumir muita memória se os clientes criarem mementos com frequência
  2. O zelador deve acompanhar o ciclo de vida do originador
  3. Pode ser complexo garantir que apenas o originador tenha acesso ao estado do memento
  4. Pode ser custoso em termos de performance para objetos que têm muito estado interno

Considerações de Implementação

  • 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