Eu tenho uma classe de dados como esta:
data class Calculation(
val calculationType: String = "Multiplication", // or "Division"
val firstOperand: Int,
val secondOperand: Int,
val actualResult: Int = if (calculationType == "Multiplication") {
firstOperand * secondOperand
} else {
firstOperand / secondOperand
}
)
Notei que há um acoplamento forte entre os diferentes membros deste data class
.
Fiquei pensando se isso pode levar a um comportamento problemático ou pode anular o propósito das classes de dados? Esse nível de complexidade já significaria que eu deveria usar um regular class
em vez disso?
Não há problema em fornecer valores padrões para uma classe de dados, mesmo quando eles são derivados de outros parâmetros. Afinal, é apenas um valor padrão e pode ser definido para qualquer outra coisa quando o objeto é construído, e o valor final pode ser completamente independente dos outros parâmetros.
Da semântica do seu exemplo específico, no entanto, parece que não deveria ser possível definir
actualResult
para nada além do valor padrão. Nesse caso, eu declararia a classe assim:Isso é diferente porque
actualResult
não pode mais ser definido, é uma propriedade totalmente derivada que é calculada quando o objeto é criado.actualResult
não é mais levado em conta quando as funções de classe de dados adicionais (equals()
,hashCode()
,toString()
,component*(),
copy()
) são criadas pelo compilador 1 . Afinal, a identidade de uma instância não dependeactualResult
mais de .Use-o somente quando os outros parâmetros nos quais o cálculo se baseia forem
val
, nãovar
.Se você não quiser desperdiçar memória armazenando dados derivados, você sempre pode calculá-los rapidamente:
Agora a propriedade não é mais calculada quando o objeto é criado , ela é calculada toda vez que é acessado . O resultado será o mesmo (já que as outras propriedades são
val
e não podem mudar ao longo do tempo), mas em vez de consumir mais memória, agora aumenta um pouco a carga na CPU quando é acessada várias vezes.Não use isso quando o cálculo for caro. Quando as outras propriedades forem,
var
você pode considerar refatoraractualResult
para ser uma função completa, para que seu comportamento dinâmico fique mais claro para o chamador.E, por fim, você pode até mesmo alterá-lo para ser uma propriedade que é calculada preguiçosamente:
Como no exemplo anterior,
actualResult
ele só é calculado quando acessado, mas o resultado do primeiro cálculo é armazenado para que qualquer acesso subsequente use o resultado armazenado em vez de repetir o cálculo.Use isto somente quando
val
e nãovar
e1 O compilador só cria essas funções para propriedades declaradas no construtor primário, não no corpo da classe: https://kotlinlang.org/docs/data-classes.html