2012-09-05 11 views
8

Soy bastante nuevo en Scala, y estoy escribiendo una biblioteca API y tratando de usar solo vals y objetos inmutables (cuando sea posible). Estoy tratando de decidir la forma correcta de modelar los objetos. Supongamos que hay varios objetos "Post", que comparten algunos campos comunes, y cada uno añade sus propios campos específicos:Scala Extendiendo Clase abstracta paramétrica

abstract class Post(val id: Int, val name: String, ...) 
case class TextPost(val id: Int, val name: String, ..., val text: String) extends Post(id, name, ...) 
case class PhotoPost(val id: Int, val name: String, ..., val url: String) extends Post(id, name, ...) 

Este método agrega una gran cantidad de declaraciones repetitivas y el código de la caldera de la placa, sobre todo cuando se trata de muchas Las subclases de publicaciones y campos compartidos se declaran en la clase abstracta. La forma en que lo veo, esto es causado por el uso de vals que solo puede ser inicializado por el constructor. ¿Hay una mejor manera de crear las relaciones detalladas aquí, o debo sufrir esto por querer usar solo objetos inmutables?

Respuesta

8

En primer lugar, los modificadores val en los constructores de la clase de caso son redundantes, el compilador de Scala se los dará "gratis" (es una de las características de las clases de casos). Si en realidad se trató de compilar ese, se verá que se produce un error debido a la imperiosa no declarada:

abstract class Post(val id: Int, val name: String) 
case class TextPost(id: Int, name: String) extends Post(id, name) 
case class PhotoPost(id: Int, name: String) extends Post(id, name) 

<console>:10: error: overriding value id in class Post of type Int; 
value id needs `override' modifier 
      case class PhotoPost(id: Int, name: String) extends Post(id, name) 
           ^

Yo personalmente recomiendo usar clases abstractas con argumentos de constructor lo menos posible. Scala tiene rasgos que hacen un mejor trabajo aquí. En lugar de argumentos de constructor, usted declara (abstractamente) los campos; luego patear las clases de casos y que se les debe hacer sus argumentos de forma automática vals, ya está resuelto:

trait Post { def id: Int; def name: String } 
case class TextPost(id: Int, name: String, text: String) extends Post 
case class PhotoPost(id: Int, name: String, url: String) extends Post 

Por otra parte, si se agrega sealed a la trait Post, se puede utilizar con seguridad los subtipos de Post en la coincidencia de patrones sin accidentalmente casos faltantes

+0

¡Gracias por la respuesta! En términos de código de placa de caldera, este método básicamente me ahorra declarar cada parámetro en clases derivadas como un valor, pero aún debo repetir todos los parámetros en cada declaración, ¿verdad? Estoy enfatizando esto, porque tengo 8 subclases y 15 campos compartidos, y esto parece ser un gran caso SECO. Pero entiendo por su respuesta que no hay forma de evitar esto, ¿verdad? – orrsella

+1

La única otra alternativa es _no_ implementar la interfaz común ('Publicación'). Eso significa que debe _componer_ el tipo para contenerlo, pero no sé si eso es lo que quiere: 'mensaje de la clase de caso (id: Int, nombre: Cadena); clase de caso TextPost (publicación: Publicación, texto: Cadena) '. –

+5

No creo que esta respuesta sea suficiente ya que no responde la pregunta de la placa de la caldera ... –

Cuestiones relacionadas