2012-05-18 11 views
15

Sé que no se te permite heredar de las clases de casos, pero ¿cómo harías cuando realmente lo necesitas? Tenemos dos clases en una jerarquía, ambas contienen muchos campos, y debemos poder crear instancias de ambas. Aquí está mi opciones:¿Cómo usar una clase de caso cuando se necesita una jerarquía?

  • Si me gustaría hacer la superclase de una clase habitual en lugar de una clase de caso - que iba a perder toda la bondad de clase caso como toString, iguales, métodos hashCode etc.
  • Si Lo mantengo como una clase de caso, rompería la regla de no heredar de las clases de casos.
  • Si utilizo la composición en la clase secundaria - tendría que escribir muchos métodos y redirigirlos a la otra clase - lo que significaría mucho trabajo y me sentiría no scalaish.

¿Qué debo hacer? ¿No es un problema bastante común?

Respuesta

9

Sí esto es un problema recurrente, wha t Sugeriría crear un rasgo con todas las propiedades principales, crear una clase de caso que simplemente lo implemente y luego otra que herede con más propiedades.

sealed trait Parent { 
    /* implement all common properties */ 
} 

case class A extends Parent 

case class B extends Parent { 
    /*add all stuff you want*/ 
} 

Una buena manera de verlo es un árbol, los rasgos son nodos y las clases de casos son hojas.

Puede usar un rasgo o una clase abstracta dependiendo de sus necesidades para el padre. Sin embargo, evite usar una clase porque podría crear instancias de ella, lo que no sería elegante.

EDIT: Como se sugiere en los comentarios, puede sellar el rasgo para tener excepciones en la compilación si no todas las clases de casos están cubiertas en un patrón coincidente. Se explica, por ejemplo, en el capítulo 15.5 de "Programación en Scala"

+6

Sellado el rasgo también sería una buena idea. – agilesteel

3

exploré este tema, así, que yo sepa, lo mejor que vas a conseguir es:

que cada clase de caso se extienden desde un rasgo común que define abstractos propiedades de cada clase deben implementar caso

no elimina el texto modelo (en absoluto), sino que define un contrato de sus clases de casos deben cumplir, sin perder de caso conjunto de características de clase ...

6

¿Qué hay de reemplazar la herencia con la delegación?

Si sus dos clases en la jerarquía tienen muchos campos compartidos, entonces la delegación podría reducir la cantidad de código repetitivo? De este modo:

case class Something(aa: A, bb: B, cc: C, payload: Payload) 

sealed abstract class Payload 

case class PayloadX(xx: X) extends Payload 
case class PayloadY(yy: Y) extends Payload 

Y entonces se crearía Something casos de este modo:

val sth1 = Something('aa', 'bb', 'cc', PayloadX('xx')) 
val sth2 = Something('aa', 'bb', 'cc', PayloadY('yy')) 

Y que podría hacer la coincidencia de patrones:

sth1 match { 
    case Something(_, _, _, PayloadX(_)) => ... 
    case Something(_, _, _, PayloadY(_)) => ... 
} 

Beneficios: (?)

  • Cuando se declara PayloadX y PayloadY, usted no tiene que repetir todos los campos en Algo.

  • Al crear instancias de Something(... Payload(..)), se puede reutilizar el código que crea Something, tanto cuando se crea un Something(... PayloadX(..)) y ...PayloadY.

inconvenientes: (?)

  • Quizás PayloadX y Y en su caso son en realidad verdaderos subclases de Something, quiero decir, en su caso, tal delegación es semánticamente mal?

  • Usted tendría que escribir something.payload.whatever en lugar de simplemente something.whatever (supongo que esto podría ser bueno o malo dependiendo de su caso en particular?)

+0

Otro inconveniente: ya no podrá hablar sobre tipos específicos en las firmas de métodos, siempre será "Algo". – Vituel

Cuestiones relacionadas