¿Cuáles son las ventajas de usar rasgos en lugar de clases abstractas?


81

¿Alguien puede explicar los rasgos en Scala? ¿Cuáles son las ventajas de los rasgos sobre la extensión de una clase abstracta?

Respuestas:


80

La respuesta corta es que puede usar múltiples rasgos, son "apilables". Además, los rasgos no pueden tener parámetros de constructor.

Así es como se apilan los rasgos. Tenga en cuenta que el orden de los rasgos es importante. Se llamarán de derecha a izquierda.

class Ball {
  def properties(): List[String] = List()
  override def toString() = "It's a" +
    properties.mkString(" ", ", ", " ") +
    "ball"
}

trait Red extends Ball {
  override def properties() = super.properties ::: List("red")
}

trait Shiny extends Ball {
  override def properties() = super.properties ::: List("shiny")
}

object Balls {
  def main(args: Array[String]) {
    val myBall = new Ball with Shiny with Red
    println(myBall) // It's a shiny, red ball
  }
}

4
La falta de parámetros de constructor casi se compensa usando parámetros de tipo en rasgos.
Jus12

19

Este sitio ofrece un buen ejemplo del uso de rasgos. Una gran ventaja de los rasgos es que puede extender varios rasgos, pero solo una clase abstracta. Los rasgos resuelven muchos de los problemas con la herencia múltiple pero permiten la reutilización del código.

Si conoces ruby, los rasgos son similares a los mix-ins


5
package ground.learning.scala.traits

/**
 * Created by Mohan on 31/08/2014.
 *
 * Stacks are layered one top of another, when moving from Left -> Right,
 * Right most will be at the top layer, and receives method call.
 */
object TraitMain {

  def main(args: Array[String]) {
    val strangers: List[NoEmotion] = List(
      new Stranger("Ray") with NoEmotion,
      new Stranger("Ray") with Bad,
      new Stranger("Ray") with Good,
      new Stranger("Ray") with Good with Bad,
      new Stranger("Ray") with Bad with Good)
    println(strangers.map(_.hi + "\n"))
  }
}

trait NoEmotion {
  def value: String

  def hi = "I am " + value
}

trait Good extends NoEmotion {
  override def hi = "I am " + value + ", It is a beautiful day!"
}

trait Bad extends NoEmotion {
  override def hi = "I am " + value + ", It is a bad day!"
}

case class Stranger(value: String) {
}
Salida:

List (soy Ray
, Soy Ray, ¡es un mal día!
, Soy Ray, ¡es un hermoso día!
, Soy Ray, ¡es un mal día!
, Soy Ray, ¡es un hermoso día!
)




1

De manera similar a las interfaces en Java, los rasgos se utilizan para definir tipos de objetos especificando la firma de los métodos compatibles.

A diferencia de Java, Scala permite que los rasgos se implementen parcialmente; es decir, es posible definir implementaciones predeterminadas para algunos métodos.

A diferencia de las clases, los rasgos pueden no tener parámetros de constructor. Los rasgos son como clases, pero que definen una interfaz de funciones y campos que las clases pueden proporcionar valores e implementaciones concretas.

Los rasgos pueden heredarse de otros rasgos o de clases.


1

Cito del sitio web del libro Programación en Scala, Primera Edición y más específicamente la sección llamada "¿ Tratar o no trazar? " Del Capítulo 12.

Siempre que implemente una colección reutilizable de comportamiento, tendrá que decidir si desea usar un rasgo o una clase abstracta. No existe una regla firme, pero esta sección contiene algunas pautas a considerar.

Si el comportamiento no se reutilizará, conviértalo en una clase concreta. Después de todo, no es un comportamiento reutilizable.

Si puede reutilizarse en varias clases no relacionadas, conviértalo en un rasgo. Solo los rasgos se pueden mezclar en diferentes partes de la jerarquía de clases.

Hay un poco más de información en el enlace anterior sobre los rasgos y le sugiero que lea la sección completa. Espero que esto ayude.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.