84 votes

Héritage de la classe de cas Scala

J'ai une application basée sur Squeryl. Je définir mes modèles comme des classes de cas, principalement parce que je trouve pratique d'avoir des méthodes de copie.

J'ai deux modèles qui sont strictement liés. Les champs sont les mêmes, de nombreuses opérations sont en commun, et ils doivent être stockés dans la même table DB. Mais il y a certains comportements qui n'a de sens que dans un des deux cas, ou qui fait sens dans les deux cas, mais ils sont différents.

Jusqu'à présent je n'ai utilisé qu'un seul cas de classe, avec un drapeau qui distingue le type du modèle, et toutes les méthodes qui diffèrent en fonction du type de modèle commencez avec un si. C'est ennuyeux et pas tout à fait le type de coffre-fort.

Ce que j'aimerais faire, c'est le facteur le comportement et les champs chez un ancêtre de la classe de cas et d'avoir les deux modèles héritent de celui-ci. Mais, comme je le comprends, d'hériter de classes de cas, c'est mal vu dans la Scala, et est même interdite si le sous-classe est elle-même une classe de cas (pas mon cas).

Quels sont les problèmes et les pièges je devrais être au courant en héritant d'une classe de cas? Est-il judicieux dans mon cas, de le faire?

109voto

Malte Schwerhoff Points 5713

Ma manière préférée d'éviter l'héritage de classe de cas sans duplication de code est assez évidente: créez une classe de base commune (abstraite):

 abstract class Person {
  def name: String
  def age: Int
  // address and other properties
  // methods (ideally only accessors since it is a case class)
}

case class Employer(val name: String, val age: Int, val taxno: Int)
    extends Person

case class Employee(val name: String, val age: Int, val salary: Int)
    extends Person
 


Si vous voulez être plus fin, regroupez les propriétés en traits individuels:

 trait Identifiable { def name: String }
trait Locatable { def address: String }
// trait Ages { def age: Int }

case class Employer(val name: String, val address: String, val taxno: Int)
    extends Identifiable
    with    Locatable

case class Employee(val name: String, val address: String, val salary: Int)
    extends Identifiable
    with    Locatable
 

40voto

Kai Sellgren Points 8423

Puisque c'est un sujet intéressant pour de nombreux, permettez-moi de jeter un peu de lumière ici.

Je recommande fortement d'utiliser l'approche suivante:

// You could mark it as 'sealed'. Explained later.
sealed trait Person {
  def name: String
}

case class Employee(
  override val name: String,
  salary: Int
) extends Person

case class Tourist(
  override val name: String,
  bored: Boolean
) extends Person

Oui, vous devez dupliquer les champs. Si vous ne le faites pas, il ne serait tout simplement pas possible de mettre en œuvre correcte de l'égalité parmi d'autres problèmes.

Cependant, vous n'avez pas besoin de dupliquer les méthodes/fonctions.

Si la duplication de quelques propriétés, c'est que beaucoup d'importance pour vous, puis utilisez les classes régulières, mais n'oubliez pas qu'ils ne s'adaptent pas bien FP.

Dans le cas où vous vous demandez ce qu'est un scellé les moyens de caractère-c'est quelque chose qui peut être prolongé que dans le même fichier. Qui est, les deux classes de cas ci-dessus doivent être dans le même fichier. Cela permet exhaustive compilateur vérifie:

val x = Employee(name = "Jack", salary = 50000)

x match {
  case Employee(name) => println(s"I'm $name!")
}

Donne une erreur:

warning: match is not exhaustive!
missing combination            Tourist

Ce qui est vraiment utile. Maintenant vous n'oubliez pas de traiter avec les autres types d' Persons (les gens). C'est essentiellement ce que l' Option classe Scala n'.

Si cela n'a pas d'importance pour vous, alors vous pourriez le faire non scellées et de jeter le cas de classes dans leurs propres fichiers.

13voto

Jens Schauder Points 23468

des classes de cas sont parfaits pour les objets de valeur, c'est à dire des objets qui ne changent pas toutes les propriétés, et peuvent être comparés avec d'égal à égal.

Mais la mise en œuvre est égal à la présence de l'héritage est plutôt compliqué. Considérons deux classes:

class Point(x : Int, y : Int)

et

class ColoredPoint( x : Int, y : Int, c : Color) extends Point

Ainsi, selon la définition de la ColorPoint(1,4,rouge) doit être égal au Point(1,4), ils sont au même Point, après tout. Donc ColorPoint(1,4,bleu) doit être égal à Point(1,4), droit? Mais bien sûr ColorPoint(1,4,rouge) ne devrait pas égal ColorPoint(1,4,bleu), parce qu'ils ont des couleurs différentes. Là vous allez, une propriété de base de l'égalité, la relation est brisée.

mise à jour

Vous pouvez utiliser l'héritage de traits de résoudre beaucoup de problèmes, comme décrit dans une autre réponse. Encore plus de flexibilité est souvent d'utiliser des classes de type. Voir Quelles sont les classes de type de Scala utile pour? ou http://www.youtube.com/watch?v=sVMES4RZF-8

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X