[Delphi] Design Patterns GoF – Prototype

Olá, leitores! Depois de um graaaande tempo de recesso, volto à ativa para continuar a série de artigos sobre Design Patterns. Peço desculpas pela ausência e agora prometo que estarei sempre por perto!
Cutting to the chase, o próximo padrão de projeto da pauta é o Prototype. Mesmo que você já o conheça, gostaria de convidá-lo para acompanhar este artigo. Tenho algumas observações e detalhes para fazer sobre este padrão de projeto.

Introdução

Assim como aconteceu com o meu estudo anterior, sobre o Factory Method, o padrão Prototype também me deixou conturbado. A princípio, entendi a mecânica do padrão, mas ainda não conseguia visualizá-lo em um ambiente real. Como você sabem, o maior intuito dessa série de artigos é fugir dos exemplos tradicionais encontrados da internet e apresentar cenários mais próximos da realidade, portanto, eu queria, a todo custo, encontrar um sentido concreto para o Prototype.

Li vários artigos e também discuti o padrão com os colegas de trabalho (algo que gosto muito de fazer) e, aos poucos, notei que o Prototype é mais comum do que parece. Em breves palavras, o objetivo principal deste padrão é copiar o estado e propriedades de um objeto já existe para um novo objeto.

Em outras palavras, O Prototype é geralmente utilizado para criar um clone de um objeto, de forma que este possa receber novos valores para os atributos sem impactar o objeto original.

Muitos programadores Delphi devem conhecer, por exemplo, o método CloneCursor da classe TClientDataSet:

Este método clona o TClientDataSet indicado no parâmetro, mantendo (opcionalmente) os filtros, índices e outras configurações, atribuindo-os a um novo objeto (chamador do método). Oras, portanto, poderíamos considerar que há um Prototype nessa operação. Claro, não significa necessariamente que este método foi implementado com este padrão, mas seria um exemplo clássico.

Exemplos que provavelmente usam o Prototype

Quando você abrir o Google Chrome, veja os menus que são exibidos ao clicar com o botão direito em uma aba. Um deles é o “Duplicar” que, obviamente, cria uma cópia da aba atual:

Menu "Duplicar" do Google Chrome

Porém, observe que o navegador não só duplica a aba, como também copia outras propriedades, como a posição da página. Se o usuário estiver no final da página e acessar essa opção do menu, a aba copiada também exibirá a página no mesmo ponto. Poderíamos afirmar, então, que essa ação clona a aba atual. O Prototype cairia perfeitamente nessa funcionalidade. Talvez até tenha sido desenvolvida com este padrão.

Outra aplicação do Prototype são as funcionalidades “temporárias”. Imagine um sistema que possua uma funcionalidade de troca de temas visuais, mas que permita que o usuário “experimente” o tema, de modo temporário, antes de efetivamente aplicá-lo. Ao selecionar o tema, o desenvolvedor pode utilizar um Prototype para clonar os aspectos visuais e aplicar o novo tema temporariamente. Se o usuário confirmar a utilização deste tema, o objeto clonado sobrescreve o objeto original, passando a exibir o novo tema permanentemente. Caso contrário, o clone é descartado e o objeto (tema) original é restaurado. Interessante, não?

Exemplo de codificação do Prototype

Para exemplificar o uso do Prototype, pensei em um gerenciador de reuniões. Imagino que você já deve ter pensando: “Acho que utilizaremos o padrão para clonar reuniões existentes, evitando que o usuário tenha que preencher tudo novamente”. É isso mesmo! 🙂

O propósito do conjunto de códigos a seguir é permitir que o usuário clone uma reunião (que é um objeto existente), criando uma nova reunião (um novo objeto), copiando todos os valores dos seus atributos.

Primeiramente, a implementação da classe de reunião:

Observe que declaramos uma função chamada “Clonar”. A implementação dessa função é o trabalho principal do Prototype:

Na nossa aplicação cliente, teremos uma lista ou tabela de reuniões. Cada uma delas será um objeto e, para armazenar todas elas, trabalharemos com uma lista de objetos (TObjectList). No exemplo, chamarei essa lista de ListaReunioes:

Sendo assim, se o usuário optar por duplicar (clonar) uma reunião, faríamos os seguintes passos:

  • Selecionar o objeto da reunião na lista de objetos;
  • Clonar a reunião;
  • Adicionar o clone na lista de objetos, para que esse também possa ser clonado posteriormente.

Perfeito! Ao clonar a reunião, todas as propriedades (nome, data, hora, categoria e participantes) são copiados para o novo objeto, poupando o tempo que o usuário teria em informá-las novamente.

O exemplo é básico, apresentando uma classe que possui apenas cinco atributos. Pense, agora, em classes maiores, com vários atributos e estados. O benefício de uso do Prototype seria evidente.

Conclusão

Ficou complicado de entender? Sem problemas! Baixe o exemplo completo no link abaixo e confira cada linha de código para compreender melhor o funcionamento.

Ah, nesse projeto de exemplo, codifiquei a parte visual. A lista de reuniões é exibida em uma TListBox e no rodapé da aplicação há dois botões. O primeiro (Nova) cria uma nova reunião, enquanto o segundo (Duplicar) clona a reunião atualmente selecionada. Observe atentamente a diferença na implementação de cada um.

 

Qualquer dúvida, estarei à disposição, pessoal!
Um grande abraço e até o próximo artigo!


André Celestino