Como lidar com diversos casos de programação defensiva?
-
21-12-2019 - |
Pergunta
Este é um exemplo de cópia defensiva em Java Efetivo.Suponha que esse cenário em minhas questões subjacentes precise de uma cópia defensiva e não possa fazer um comentário solicitando ao cliente que evite a passagem de objetos mutantes.
public Period(Date start, Date end) {
this.start = new Date(start.getTime());
this.end = new Date(end.getTime());
}
Questões:
O que fazer se
Date
não tinha um construtor para se absorver, para me tornar mais geral, um objeto é passado sem nenhum mecanismo para se replicar, e tal objeto não nos pertence, ou seja, não podemos alterá-lo de forma alguma?E se o construtor usasse o parâmetro de tipo como argumento, digamos
Period(T object)
e T podem ser mutáveis, portanto precisam de cópia defensiva.Não temos ideia do que é T.Como fazer cópia defensiva neste caso?O que é uma interface é passada onde algumas de suas subclasses possuem um construtor como
Date
criar um objeto próprio e algumas de suas subclasses não possuem nenhum mecanismo para fazer isso?Quão profundo devemos copiar defensivamente?Digamos que copiamos um array, mas os elementos do array eram mutáveis?
Solução
- Se todo o seu estado estiver disponível, você poderá extrair seu estado e construir um novo objeto sozinho.Caso contrário, você não poderá fazer nada a respeito, exceto usar truques desagradáveis de reflexão ou serialização.
- Se T não for uma instância de uma classe que permita copiar a si mesma, você não poderá fazer nada.
- Você não pode fazer nada sobre isso.
- Depende.
Ao ler sua pergunta, parece que você gostaria de aplicar o conselho da "cópia defensiva" em todos os lugares.Você não deveria.Na maioria das vezes, o código que usa objetos mutáveis deseja uma referência ao objeto original, e não uma cópia.Especialmente se o que você obtém como argumento for uma instância de uma classe ou interface abstrata.
Você é forçado a fazer uma cópia defensiva de Date porque é um tipo de valor mutável que não deveria ser mutável e não seria se tivesse sido projetado corretamente.Se você promover a imutabilidade para tipos de valor, as cópias defensivas se tornarão desnecessárias.Para tipos sem valor, geralmente você não deseja uma cópia, mas uma referência ao objeto.
Outras dicas
- .
- Se você não puder alterar o estado do objeto de qualquer maneira, você não precisa de uma cópia defensiva.
- A única coisa que você pode fazer é assumir a implementação provável de t e verificá-los com instance de .
- o mesmo que 2.
- a seu critério.Se você assumir que a modificação de elementos da matriz pode quebrar seu programa em outros lugares, você deve copiá-los também.
Programação defensiva é importante quando os objetos que você passam para um método é mutável.Uma boa prática (também descrita no livro Java efetivo) é torná-los imutáveis.
- .
- Se a aula de data não for final, você pode escrever uma aula de wrapper para ele, que é subclasse da data.
- depende.Provavelmente, não haverá necessidade de clonar.
- Não deveria incomodar você.O implementador de uma interface deve cuidar de problemas de sincronização.Geralmente, é uma boa prática passar interfaces em vez de suas implementações.
- Para coleções padrão Java há muitos métodos de utilidade na classe Java.util.collections, como UNModFiaBlelista e UNMdifiaBlemap, destinados a usar para programação defensiva.