¿Cuál es la ventaja de usar una clase abstracta en lugar de un rasgo (aparte del rendimiento)? Parece que las clases abstractas pueden ser reemplazadas por rasgos en la mayoría de los casos.
371
Se me ocurren dos diferencias
Hay una sección en Programación en Scala llamada "¿Rasgo o no rasgo?" que aborda esta pregunta. Como la primera edición está disponible en línea, espero que esté bien citar todo aquí. (Cualquier programador serio de Scala debería comprar el libro):
Como @Mushtaq Ahmed mencionó, un rasgo no puede tener ningún parámetro pasado al constructor primario de una clase.
Otra diferencia es el tratamiento de
super
.Vea el resto del Capítulo 12 para más detalles.
Edición 1 (2013):
Hay una sutil diferencia en la forma en que las clases abstractas se comportan en comparación con los rasgos. Una de las reglas de linealización es que conserva la jerarquía de herencia de las clases, lo que tiende a impulsar las clases abstractas más adelante en la cadena, mientras que los rasgos pueden mezclarse felizmente. En ciertas circunstancias, es preferible estar en la última posición de la linealización de clases , por lo que podrían usarse clases abstractas para eso. Ver linealización de clase restrictiva (orden de mezcla) en Scala .
Edición 2 (2018):
A partir de Scala 2.12, el comportamiento de compatibilidad binaria del rasgo ha cambiado. Antes de 2.12, agregar o eliminar un miembro al rasgo requería la compilación de todas las clases que heredan el rasgo, incluso si las clases no han cambiado. Esto se debe a la forma en que se codificaron los rasgos en JVM.
A partir de Scala 2.12, los rasgos se compilan en interfaces Java , por lo que el requisito se ha relajado un poco. Si el rasgo hace algo de lo siguiente, sus subclases aún requieren recompilación:
Pero si el rasgo no lo hace, ahora puede actualizarlo sin romper la compatibilidad binaria.
fuente
If outside clients will only call into the behavior, instead of inheriting from it, then using a trait is fine
- ¿Alguien podría explicar cuál es la diferencia aquí?extends
vswith
?extends
ywith
. Es puramente sintáctico. Si hereda de varias plantillas, la primera obtieneextend
, todas las demás obtienenwith
, eso es todo. Piensewith
como una coma:class Foo extends Bar, Baz, Qux
.Para lo que sea que valga la pena, la Programación en Scala de Odersky et al recomienda que, cuando dudes, uses rasgos. Siempre puede cambiarlos a clases abstractas más adelante si es necesario.
fuente
Aparte del hecho de que no puede extender directamente múltiples clases abstractas, pero puede mezclar múltiples rasgos en una clase, vale la pena mencionar que los rasgos son apilables, ya que las súper llamadas en un rasgo están vinculadas dinámicamente (se refiere a una clase o rasgo mezclado antes) el actual).
De la respuesta de Thomas en Diferencia entre clase abstracta y rasgo :
fuente
Al extender una clase abstracta, esto muestra que la subclase es de un tipo similar. Creo que este no es necesariamente el caso cuando se usan rasgos.
fuente
En Programming Scala, los autores dicen que las clases abstractas hacen una relación clásica "es-una" orientada a objetos, mientras que los rasgos son una forma de composición de escala.
fuente
Las clases abstractas pueden contener comportamiento: pueden parametrizarse con argumentos de constructor (que los rasgos no pueden) y representan una entidad de trabajo. En cambio, los rasgos solo representan una característica única, una interfaz de una funcionalidad.
fuente
trait Enumerable
con muchas funciones auxiliares, no las llamaría comportamiento sino solo funcionalidad relacionada con una característica.fuente