Navegando por algum código que escrevi, me deparei com a seguinte construção que me fez pensar. À primeira vista, parece bastante limpo. Sim, no código real, o getLocation()
método tem um nome um pouco mais específico que descreve melhor exatamente qual local ele obtém.
service.setLocation(this.configuration.getLocation().toString());
Nesse caso, service
é uma variável de instância de um tipo conhecido, declarada dentro do método this.configuration
é transmitido ao construtor da classe e é uma instância de uma classe implementando uma interface específica (que exige um getLocation()
método público ). Portanto, o tipo de retorno da expressão this.configuration.getLocation()
é conhecido; especificamente neste caso, é a java.net.URL
, enquanto service.setLocation()
quer a String
. Como os dois tipos String e URL não são diretamente compatíveis, é necessário algum tipo de conversão para ajustar a estaca quadrada no orifício redondo.
No entanto , de acordo com a Lei de Demeter como citado em Clean Code , um método f na classe C só deve chamar métodos em C , objetos criados por ou passados como argumentos para f , e objetos realizada em variáveis de instância de C . Qualquer coisa além disso (a final toString()
no meu caso particular acima, a menos que você considere um objeto temporário criado como resultado da própria invocação do método, caso em que toda a Lei parece discutível) é desaprovada.
Existe um raciocínio válido por que uma chamada como a acima, dadas as restrições listadas, deve ser desencorajada ou até proibida? Ou eu estou apenas sendo muito cuidadoso?
Se eu fosse implementar um método URLToString()
que simplesmente chama toString()
um URL
objeto (como o retornado por getLocation()
) passado a ele como parâmetro e retorna o resultado, eu poderia envolver a getLocation()
chamada nele para obter exatamente o mesmo resultado; efetivamente, eu apenas moveria a conversão um passo para fora. De alguma forma isso seria aceitável? ( Parece -me, intuitivamente, que isso não deve fazer nenhuma diferença, pois tudo o que faz é mudar um pouco as coisas. No entanto, seguindo a letra da Lei de Deméter, como citado, seria aceitável, pois eu estaria operando diretamente em um parâmetro para uma função.)
Faria alguma diferença se isso fosse algo um pouco mais exótico do que chamar toString()
um tipo padrão?
Ao responder, lembre-se de que alterar o comportamento ou API do tipo de que a service
variável é não é prático. Além disso, por uma questão de argumento, digamos que alterar o tipo de retorno getLocation()
também seja impraticável.
fonte
A lei de Deméter é uma diretriz de design, não uma lei a ser seguida religiosamente.
Se você achar que suas classes são suficientemente dissociadas, não há nada errado com a linha,
this.configuration.getLocation()
especialmente se, como você diz, não for prático alterar outras partes da API.Tenho certeza de que o cliente ficará perfeitamente feliz, mesmo que você faça a Lei de Deméter em pedaços, desde que você entregue o que ele quer e no prazo. O que não é uma desculpa para criar software ruim, mas um lembrete para ser pragmático ao desenvolver software.
fonte
this.configuration
é uma variável de instância de um tipo de interface conhecida, chamar um método definido por essa interface parece bom, mesmo de acordo com uma interpretação estrita. Sim, eu sei que é uma diretriz, assim como KISS, SOLID, YAGNI e assim por diante. Existem muito poucas, se é que existem, "leis" (no sentido jurídico) no desenvolvimento geral de software.A única coisa que consigo pensar em não escrever código como esse é o que se
this.configuration.getLocation()
retorna nulo? Depende do código circundante e do público-alvo usando esse código. Mas, como Marco diz - a lei de Deméter é uma regra de ouro - é bom seguir, mas não quebre as costas desnecessariamente.fonte
this.configuration.getLocation()
retornar nulo, então (a) provavelmente nunca teríamos chegado tão longe, ou (b) algo catastrófico aconteceu nesse ínterim; nesse caso, eu gostaria que o código falhasse. Portanto, embora esse seja definitivamente um ponto válido em geral, nesse caso em particular, é bastante seguro dizer que não se aplica. Além disso, ao redor de tudo isso e muito mais, há um manipulador de exceção projetado especificamente para lidar com esse tipo de falhas inesperadas.Seguir estritamente a Lei de Demeter significa que você deve implementar um método no objeto de configuração como:
mas pessoalmente eu não me incomodaria porque esta é uma situação tão pequena e, de qualquer forma, suas mãos estão meio empatadas por causa da API que você não pode mudar. As regras de programação são sobre o que você deve fazer quando tem uma escolha, mas às vezes você não tem uma escolha.
fonte