Entendendo o Padrão Prototype
O padrão de projeto Prototype é um padrão criacional que permite a replicação de objetos existentes sem que o código dependa de suas classes específicas. Em termos práticos, este padrão fundamenta-se no conceito de clonagem. Em vez de instanciar um novo objeto do zero e configurar todos os seus atributos manualmente, utilizamos uma instância existente (o protótipo) como base para gerar novas cópias.
Ao lidar com clonagem em linguagens como Java, é crucial distinguir entre dois conceitos fundamentais:
- Shallow Copy (Cópia Rasa): Copia os valores dos campos primitivos. No caso de campos que são referências a objetos, apenas o endereço de memória é copiado, o que significa que o objeto original e o clonado compartilharão a mesma instância do objeto interno.
- Deep Copy (Cópia Profunda): Além de copiar os primitivos, cria novas instâncias para todos os objetos referenciados internamente, garantindo independência total entre o protótipo e o clone.
Implementação Prática
Abaixo, apresentamos uma implementação em Java utilizando a interface Cloneable para demonstrar a técnica de Deep Copy.
1. Definição da Classe Dependente
Primeiro, definimos uma classe que representa uma dependência interna, como o histórico profissional de um usuário.
public class HistoricoProfissional implements Cloneable {
private String periodo;
private String empresa;
public HistoricoProfissional(String periodo, String empresa) {
this.periodo = periodo;
this.empresa = empresa;
}
// Getters e Setters omitidos
@Override
protected Object clone() throws CloneNotSupportedException {
// Implementação padrão de cópia rasa para esta classe simples
return super.clone();
}
@Override
public String toString() {
return "HistoricoProfissional{periodo='" + periodo + "', empresa='" + empresa + "'}";
}
}
2. Implementação do Protótipo com Deep Copy
A classe principal implementa a lógica de clonagem profunda para garantir que o objeto interno também seja duplicado.
public class PerfilUsuario implements Cloneable {
private String nome;
private int idade;
private HistoricoProfissional historico;
public PerfilUsuario(String nome, int idade, HistoricoProfissional historico) {
this.nome = nome;
this.idade = idade;
this.historico = historico;
}
// Getters e Setters omitidos
@Override
public PerfilUsuario clone() throws CloneNotSupportedException {
// Primeiro, realiza a cópia rasa da classe principal
PerfilUsuario novoPerfil = (PerfilUsuario) super.clone();
// Em seguida, realiza a clonagem manual do objeto interno (Deep Copy)
if (this.historico != null) {
novoPerfil.historico = (HistoricoProfissional) this.historico.clone();
}
return novoPerfil;
}
@Override
public String toString() {
return "PerfilUsuario{nome='" + nome + "', idade=" + idade + ", historico=" + historico + "}";
}
}
3. Execução e Validação
O código a seguir demonstra como o Prototype se comporta e valida se as instâncias são realmente independentes.
public class ExemploPrototype {
public static void main(String[] args) throws CloneNotSupportedException {
HistoricoProfissional exp = new HistoricoProfissional("2020-2023", "Tech Corp");
PerfilUsuario original = new PerfilUsuario("Carlos Silva", 30, exp);
// Criando uma cópia via Prototype
PerfilUsuario clone = original.clone();
// Modificando o clone
clone.setNome("Carlos Souza");
System.out.println("Original: " + original);
System.out.println("Clone: " + clone);
// Verificação de independência de memória
boolean mesmoObjetoInterno = (original.getHistorico() == clone.getHistorico());
System.out.println("Mesma referência de histórico? " + mesmoObjetoInterno);
// Resultado esperado: false (Deep Copy funcional)
}
}
Considerações sobre o Uso
Em Java, a implementação do Prototype através da interface Cloneable e do método clone() é o caminho nativo, porém requer atenção redobrada. Para estruturas de objetos complexas e profundamente aninhadas, o desenvolvedor deve garantir que cada nível da hierarquia suporte a clonagem de forma correta, evitando efeitos colaterais onde alterações em um objeto clonado afetam o original inesperadamente.