Sobrescreva o clone de modo sensato
Esta é uma série baseada no entendimento de tópicos relacionados ao livro com foco no resumo.
Porquê?
Talvez você se questione porque você deveria entender sobre clonar objetos ou sobre como implementar o método clone nas classes. O fato é que muitas vezes precisaremos durante nosso código gerar objetos com mesmo conteúdo porém em uma outra instância na memória e muitas vezes esses objetos não são simples de serem instanciados, e aí onde o clone pode ser muito útil.
Dado isso vamos entender como implementamos o clone nos nossos objetos no Java.
Cloneable
Primeiro vamos entender a interface Cloneable que NÃO TEM nenhum método, isso porque ela é apenas utilizada para indicar que uma classe que implementa ela deve ter todos os atributos copiados para um novo objeto. Mas como isso ocorre?
Envolve o método clone() da classe Object que é herdado em todas as classes no Java, ou seja, além da classe herdar o método ao implementar essa interface ela garante que o comportamento desse método será modificado para cópia de cada atributo.
Como?
Para ser possível clonar a classe precisamos que ela implemente a interface Cloneable e que seja sobrescrito o método clone chamando o método através do super. Um ponto que deve ser levado em consieração é se uma superclasse já sobrescreveu esse método, pois neste caso não há necessidade de implementação, pois o clone funcionará normalmente.
Atenção!
Um dos conselhos que o livro trás é que mesmo o método originalmente retornar um Object, podemos modificar nossa sobrescrita do método pois por nosso tipo ser filho de Object será possível devido aos retornos covariantes do Java. Ou seja, garantimos de já retornarmos o tipo correto ao invés de deixarmos o cast para os clientes do método. Outro conselho é sobre tratar a exception com o try/catch porque a exceção do método clone é verificada, porém é quase impossível lançar a exceção e acaba obrigando os clientes a tratá-la.
Outro ponto que é necessário manter atenção, é sobre os tipos que são copiados, nesse caso o ideal é que seja feita a cópia do objeto através do método clone pois se não realizarmos isso estaremos apenas copiando a referência o que pode gerar inconsistências pois se a classe for mutável podemos realizar operações que impactariam o objeto origem. O mesmo deve ser realizado com coleções que estejam no objeto origem ou em sua estrutura. Como no exemplo acima, faço a cópia do campo serviço usando o clone dessa classe que de fato me retornará uma nova instância de Servico.
Quando falamos de cópias de objetos falamos de cópia simples ou profunda, a segunda esta ligada ao caso citado acima que envolve outros objetos na arvore de dependência.
Ainda nesse mesmo exemplo, se o atributo serviço fosse final, não seria possível realizar a operação de atribuição chamando o clone da classe Servico. Com isso podemos chegar a conclusão de que a estrutura de clone utilizada pela Cloneable não é compatível com situações como esta.
Conselhos
O livro aconselha que vale mais a pena fornecermos um método alternativo de cópia do objeto, através da criação de um método de cópia ou um método de fábrica de cópia que recebe como argumento a classe que tem o construtor de cópia, por exemplo:
//construtor
public Usuario(Usuaario usuario){...};
//método fabrica
public static Usuario newInstance(Usuario usuario){...};
As vantagens dessa abordagem são muitas, dentre elas: menor risco, não tem conflito com campos finais, não lança exceções verificadas, não precisa de cast, permite trabalhar com interface.
Use com cuidado...
O livro pede para evitarmos o uso da Cloneable e usarmos outras abordagens, mesmo considerando que em classes do tipo final o risco é menor. No geral não deveríamos trabalhar com cópia usando Cloneable, apenas para exceções como para cópia de arrays que são copiados de forma melhor com essa abordagem.
Cópias de objetos faz sentido para classes de dominío ou que representam objetos de transação e guardem estado.
E podemos implementar o método de cópia utilizando bibliotecas específicas para isso e não precisamos implementar a interface Cloneable nesse cenário.
Bibliotecas
No nosso dia a dia podemos trabalhar com objetos complexos que muitas vezes tem uma árvore de dependência de classes bem complicadas e daí não convém reinventarmos a roda e por isso blibliotecas como Apache Commons Lang, kostaskougios, fluidity-cloning são ótimas para utilizarmos para cópias de objetos e termos a garantia que elas realizam cópias profundas sem problemas.
Top comments (1)
Muito legal !