2010-01-05 40 views

Respuesta

60

Una clase solo puede extend one superclass, y por lo tanto, solo una clase abstracta. Si desea componer varias clases, la forma de Scala es usar mixin class composition: combina una superclase (opcional), sus propias definiciones de miembro y una o más traits. Un rasgo está restringido en comparación con las clases en que no puede tener parámetros de constructor (compare el scala reference manual).

Las restricciones de los rasgos en comparación con las clases se introducen para evitar problemas típicos con la herencia múltiple. Hay reglas más o menos complicadas con respecto a la jerarquía de herencia; podría ser mejor evitar una jerarquía donde esto realmente importa. ;-) Por lo que yo entiendo, solo puede importar si heredas dos métodos con la misma firma/dos variables con el mismo nombre de dos rasgos diferentes.

+0

No se encontrará con escenarios complicados siempre que su jerarquía sea un árbol. – Raphael

+0

@edit: puede tener conflictos sin que los supertipos hereden el mismo rasgo. Dos métodos con el mismo nombre y parámetro (tipo) listan conflicto. – Raphael

+0

@Raphael Buen punto. Traté de aclarar esto. ¿Es ahora correcto? –

5

Al menos en Scala, el sistema de rasgos tiene una forma explícita de declarar prioridad padre en una subclase para evitar problemas típicos asociados con la herencia múltiple, es decir, conflictos con métodos heredados que tienen la misma firma.

Los rasgos son similares a las interfaces de Java, pero se les permite tener implementaciones de métodos.

+0

La precedencia de la vinculación no se resuelve por los rasgos per se pero sino por la linealización de la lista de supernombre. Podrías hacer lo mismo con herencia de clase múltiple. – Raphael

12

Conceptualmente, un rasgo es un componente de una clase, no una clase en sí misma. Como tal, normalmente no tiene constructores, y no está destinado a "mantenerse por sí mismo".

Sugiero usar una clase abstracta cuando tiene un significado independiente, y rasgos cuando solo quiere agregar funcionalidad de una manera orientada a objetos. Si no está seguro entre los dos, puede encontrar que si todos sus métodos giran en torno a hacer una sola cosa, es probable que desee un rasgo.

Para un ejemplo (no específico del idioma), si su Empleado debe extender tanto "Persona" como "Clonable", haga de Person una clase base y Cloneable un rasgo.

+1

Diría que cuando todos los métodos giran en torno a hacer una sola cosa, su diseño está bien (Principio de responsabilidad única: http://en.wikipedia.org/wiki/Single_responsibility_principle). De lo contrario, el diseño debería ser un compromiso defendible. –

+0

Tienes razón, aclaré mi respuesta un poco. – Oak

49

Un aspecto de los rasgos es que son apilable. Permitir una forma restringida de AOP (alrededor de consejos).

trait A{ 
    def a = 1 
} 

trait X extends A{ 
    override def a = { 
     println("X") 
     super.a 
    } 
} 


trait Y extends A{ 
    override def a = { 
     println("Y") 
     super.a 
    } 
} 

scala> val xy = new AnyRef with X with Y 
xy: java.lang.Object with X with Y = [email protected] 
scala> xy.a 
Y 
X 
res0: Int = 1 

scala> val yx = new AnyRef with Y with X 
yx: java.lang.Object with Y with X = [email protected] 
scala> yx.a 
X 
Y 
res1: Int = 1 

La resolución de super refleja la linealización de la jerarquía de herencia.

+2

cool ... ¿Qué pasa si dos rasgos ** X ** y ** Y ** producen valores diferentes para def ** a **? –

Cuestiones relacionadas