Si está escribiendo código que utiliza muchas estructuras de datos hermosas e inmutables, las clases de casos parecen ser un regalo del cielo, y le brindan todo lo siguiente de forma gratuita con una sola palabra clave:
- Todo inmutable por defecto
- Getters definidos automáticamente
- Implementación decente de toString ()
- Compatible con equals () y hashCode ()
- Objeto complementario con el método unapply () para hacer coincidir
Pero, ¿cuáles son las desventajas de definir una estructura de datos inmutable como una clase de caso?
¿Qué restricciones impone a la clase o sus clientes?
¿Hay situaciones en las que debería preferir una clase que no sea de casos?
scala
case-class
Graham Lea
fuente
fuente
Respuestas:
Una gran desventaja: las clases de casos no pueden extender una clase de casos. Esa es la restricción.
Otras ventajas que perdió, enumeradas para completar: serialización / deserialización compatible, no es necesario usar la palabra clave "nueva" para crear.
Prefiero clases sin mayúsculas para objetos con estado mutable, estado privado o sin estado (por ejemplo, la mayoría de los componentes singleton). Clases de casos para casi todo lo demás.
fuente
Primero lo bueno:
Todo inmutable por defecto
Sí, e incluso se puede anular (usar
var
) si lo necesitaGetters definidos automáticamente
Posible en cualquier clase prefijando parámetros con
val
toString()
Implementación decenteSí, muy útil, pero factible a mano en cualquier clase si es necesario
Cumple
equals()
yhashCode()
Combinado con una fácil coincidencia de patrones, esta es la razón principal por la que las personas usan clases de casos
Objeto complementario con
unapply()
método de coincidenciaTambién es posible hacerlo a mano en cualquier clase mediante el uso de extractores.
Esta lista también debería incluir el método de copia súper poderoso, una de las mejores cosas que vienen a Scala 2.8
Luego, lo malo, solo hay un puñado de restricciones reales con clases de casos:
No puede definir
apply
en el objeto complementario utilizando la misma firma que el método generado por el compiladorSin embargo, en la práctica, esto rara vez es un problema. Se garantiza que el cambio de comportamiento del método de aplicación generado sorprenderá a los usuarios y debe desaconsejarse enérgicamente, la única justificación para hacerlo es validar los parámetros de entrada, una tarea que se realiza mejor en el cuerpo del constructor principal (que también hace que la validación esté disponible cuando se usa
copy
)No puedes subclase
Es cierto, aunque todavía es posible que una clase de caso sea un descendiente. Un patrón común es construir una jerarquía de rasgos de clases, utilizando clases de casos como los nodos hoja del árbol.
También vale la pena señalar el
sealed
modificador. Cualquier subclase de un rasgo con este modificador debe declararse en el mismo archivo. Cuando se comparan patrones con instancias del rasgo, el compilador puede advertirle si no ha verificado todas las posibles subclases concretas. Cuando se combina con clases de casos, esto puede ofrecerle un nivel muy alto de confianza en su código si se compila sin previo aviso.Como subclase de producto, las clases de casos no pueden tener más de 22 parámetros
No hay una solución real, excepto para dejar de abusar de las clases con tantos parámetros :)
También...
Otra restricción que a veces se observa es que Scala no admite (actualmente) parámetros perezosos (como
lazy val
s, pero como parámetros). La solución a esto es usar un parámetro por nombre y asignarlo a un valor perezoso en el constructor. Desafortunadamente, los parámetros por nombre no se mezclan con la coincidencia de patrones, lo que evita que la técnica se use con clases de casos, ya que rompe el extractor generado por el compilador.Esto es relevante si desea implementar estructuras de datos perezosas altamente funcionales y, con suerte, se resolverá con la adición de parámetros perezosos a una versión futura de Scala.
fuente
Creo que el principio TDD se aplica aquí: no sobre-diseño. Cuando declaras que algo es a
case class
, estás declarando mucha funcionalidad. Eso disminuirá la flexibilidad que tiene para cambiar de clase en el futuro.Por ejemplo, a
case class
tiene unequals
método sobre los parámetros del constructor. Es posible que no le importe eso cuando escriba su clase por primera vez, pero, más tarde, puede decidir que desea que la igualdad ignore algunos de estos parámetros o haga algo un poco diferente. Sin embargo, el código del cliente puede escribirse mientras tanto depende de lacase class
igualdad.fuente
Martin Odersky nos da un buen punto de partida en su curso Principios de programación funcional en Scala (Lección 4.6 - Coincidencia de patrones) que podríamos usar cuando debemos elegir entre clase y clase de caso. El capítulo 7 de Scala By Example contiene el mismo ejemplo.
Además, agregar una nueva clase Prod no implica ningún cambio en el código existente:
Por el contrario, agregar un nuevo método requiere la modificación de todas las clases existentes.
El mismo problema resuelto con clases de casos.
Agregar un nuevo método es un cambio local.
Agregar una nueva clase Prod requiere potencialmente cambiar todas las coincidencias de patrones.
Transcripción de la videolección 4.6 Coincidencia de patrones
Recuerde: debemos usar esto como un punto de partida y no como el único criterio.
fuente
Cito esto desde
Scala cookbook
porAlvin Alexander
capítulo 6:objects
.Esta es una de las muchas cosas que encontré interesantes en este libro.
Para proporcionar varios constructores para una clase de caso, es importante saber qué hace realmente la declaración de la clase de caso.
Si observa el código que genera el compilador de Scala para el ejemplo de la clase de caso, verá que crea dos archivos de salida, Person $ .class y Person.class. Si desensambla Person $ .class con el comando javap, verá que contiene un método de aplicación, junto con muchos otros:
También puede desensamblar Person.class para ver qué contiene. Para una clase simple como esta, contiene 20 métodos adicionales; esta hinchazón oculta es una de las razones por las que a algunos desarrolladores no les gustan las clases de casos.
fuente