Design Patterns — Parte 7 — Prototype

Intenção
Prototype é um padrão de design criacional que permite copiar objetos existentes sem tornar seu código dependente de suas classes.
Problema
Digamos que você tenha um objeto e deseje criar uma cópia exata dele. Como você faria? Primeiro, você deve criar um novo objeto da mesma classe. Então você precisa percorrer todos os campos do objeto original e copiar seus valores para o novo objeto.
Por exemplo, um objeto deve ser criado após uma operação de banco de dados dispendiosa. Podemos armazenar em cache o objeto, retornar seu clone na próxima solicitação e atualizar o banco de dados conforme e quando necessário, reduzindo assim as chamadas ao banco de dados.
Solução
O padrão Prototype delega o processo de clonagem para os objetos reais que estão sendo clonados. O padrão declara uma interface comum para todos os objetos que suportam a clonagem. Essa interface permite clonar um objeto sem acoplar seu código à classe desse objeto. Normalmente, essa interface contém apenas um único método clone.
A implementação do método clone é muito semelhante em todas as classes. O método cria um objeto da classe atual e transporta todos os valores de campo do objeto antigo para o novo. Você pode até copiar campos particulares porque a maioria das linguagens de programação permite que objetos acessem campos particulares de outros objetos que pertencem à mesma classe.
Um objeto que suporta a clonagem é chamado de protótipo . Quando seus objetos têm dezenas de campos e centenas de configurações possíveis, a clonagem deles pode servir como uma alternativa à subclasse.
Protótipos pré-construídos podem ser uma alternativa à subclassificação.
Eis como funciona: você cria um conjunto de objetos, configurado de várias maneiras. Quando você precisa de um objeto como o que você configurou, basta clonar um protótipo em vez de construir um novo objeto do zero.
Implementação

As classes, interfaces e objetos no diagrama de classes UML acima são os seguintes:
Prototype
- Essa é uma interface usada para os tipos de objetos que podem ser clonados.
ConcretePrototype
- Esta é uma classe que implementa a interface Prototype para clonagem em si.
Prós
- Você pode clonar objetos sem acoplar às suas classes concretas.
- Você pode se livrar do código de inicialização repetido em favor da clonagem de protótipos pré-criados.
- Você pode produzir objetos complexos de forma mais conveniente.
- Você obtém uma alternativa à herança ao lidar com predefinições de configuração para objetos complexos.
Contras
- A clonagem de objetos complexos com referências circulares pode ser muito complicada.
Exemplo

Vamos começar criando uma interface chamada IEmployee ela será nossa interface Prototype, com o seguinte código:
public interface IEmployee
{
IEmployee Clone();
string GetDetails();
}Em seguida irei criar a classe Developer que implementará minha interface IEmployee, e também irei criar a classe Manager que também implementará minha interface IEmployee. com o seguinte código:
public class Developer : IEmployee
{
public int WordsPerMinute { get; set; }
public string Name { get; set; }
public string Role { get; set; }
public string PreferredLanguage { get; set; }
public IEmployee Clone()
{
// Shallow Copy: only top-level objects are duplicated
return (IEmployee)MemberwiseClone();
// Deep Copy: all objects are duplicated
//return (IEmployee)this.Clone();
}
public string GetDetails()
{
return string.Format("{0} - {1} - {2}", Name, Role, PreferredLanguage);
}
}public class Manager : IEmployee
{
public int WordsPerMinute { get; set; }
public string Name { get; set; }
public string Role { get; set; }public IEmployee Clone()
{
return (IEmployee)MemberwiseClone();
}public string GetDetails()
{
return string.Format("{0} - {1} - {2}wpm", Name, Role, WordsPerMinute);
}
}
Em seguida irei criar o nosso console de testes:
class Program
{
static void Main(string[] args)
{
Developer dev = new Developer();
dev.Name = "Cesar Silva";
dev.Role = "Coordenador Ti";
dev.PreferredLanguage = "C#";Developer devCopy = (Developer)dev.Clone();
devCopy.Name = "Igor Kawata"; //Not mention Role and PreferredLanguage, it will copy aboveConsole.WriteLine(dev.GetDetails());
Console.WriteLine(devCopy.GetDetails());Manager manager = new Manager();
manager.Name = "Jones Roberto";
manager.Role = "Gerente";
manager.WordsPerMinute = 120;Manager managerCopy = (Manager)manager.Clone();
managerCopy.Name = "Leonidas Leme";
managerCopy.WordsPerMinute = 110;//Not mention Role, it will copy aboveConsole.WriteLine(manager.GetDetails());
Console.WriteLine(managerCopy.GetDetails());Console.ReadKey();
}
}
Como é possível observar o padrão prototype torna bem mais simples a criação de novos objetos complexos, isso daria um enorme ganho para aplicação devido a facilidade na implementação.

