2
votes

Comment récupérer des classes dérivées telles quelles à partir d'une carte?

Je dois récupérer les objets de classe dérivée stockés dans une carte avec le nom de classe respectif comme clé.

Comme indiqué ci-dessous

class PreScoreCalculator(data:Seq[Int]) extends Caluclator

Le nom de clé donné doit être obtenu objet / instance respectif de la carte

   val calcName = "PreScore"

   val opt = getCalculatorByOperationName(calcName) 

   if(opt.isInstanceOf[PreScoreCalculator] )   /// this is coming as false
      calculationController.calculate(opt)     // this is not being executed.

J'appelle comme ci-dessous

def getCalculatorByOperationName(operation:String) : Option[ Calculator]  = {
       calculatorsLookUp.get(operation)
    }

Attendez-vous à: Exécuter calculController.calculate (opt)

Erreur: Ci-dessus si la condition est fausse, donc ne pas être exécutée.

Alors, comment gérer ce problème?

Comment gérer ci-dessous, à savoir les objets constructeur par défaut?

trait Caluclator
class PreScoreCalculator(data:Seq[Int]) extends Caluclator
class BenchMarkCalculator(data:Seq[Int]) extends Caluclator


val calculatorsLookUp:Map[String, Calculator]  = Map[String, Calculator](
            "PreScore" -> new PreScoreCalculator,
             "BenchMark" -> new BenchMarkCalculator
            )


0 commentaires

3 Réponses :


1
votes

Le problème ici est sur

if(opt.map(_.isInstanceOf[PreScoreCalculator]).getOrElse(false))
  calculationController.calculate(opt.get)

car il renverra Option [Calculatrice] et non Calculatrice . Maintenant, cela ressemblera à ceci ..

val opt = getCalculatorByOperationName(calcName)

J'espère que cela vous aidera.


2 commentaires

merci, puis-je savoir pourquoi vous utilisez .map ici? si ce n'est pas le cas .isInstanceOf [PreScoreCalculator] renvoie false si la clé n'est pas "PreScore", non? pourquoi avons-nous besoin de .getOrElse (false) ???


D'accord. Premièrement, le résultat de opt est toujours Option [Calculator] et l'objet Predef de Scala offre une conversion implicite qui vous permet d'écrire key -> value comme syntaxe alternative pour la paire ( valeur clé). Dans le cas où le résultat est None, alors il ira à .getOrElse (false) donc c'est sûr.



2
votes

Vous avez un petit bug:

opt est de type Option [Calculatrice]

Dans Scala, une bonne façon de gérer cela est correspondance de modèle:

  opt.filter(_.isInstanceOf[PreScoreCalculator])
      .foreach(calculationController.calculate)

Ou faites-le d'une manière plus déclarative:

opt match {
    case Some(calculator: PreScoreCalculator) =>
      calculationController.calculate(calculator)
    case _ => // nothing to do
  }

Cependant l'utilisation de instanceOf est un peu un anti-pattern.

Comme astuce:

Utilisez println (opt.getClass) > puis vous voyez la classe .


7 commentaires

merci pour la réponse rapide, désolé cette exécution tout le temps même si la clé n'est pas PreScore. Et println (opt.getClass) donne "class scala.Some"


vous avez raison désolé - j'ai corrigé ma réponse et testé maintenant les deux cas;)


merci beaucoup, pourquoi utilisez foreach ici? Que suis-je en train d'itérer ici?


opt est de type Option [Calculatrice] . Si vous voulez en faire quelque chose, vous devez le déballer, pour l'utiliser> foreach le fait - vérifiez l'API de Option .


Merci pour la clarté, si mon PreScoreCalculator prend un constructeur à savoir PreScoreCalculator (données: Seq [Int]) comment peut-il le gérer, dans le scénario ci-dessus?


si calculer prend une calculatrice , vous le gérez comme ci-dessus - sinon vous devez ajuster votre question et ajouter la fonction calculer pour plus de clarté.


okey laissez-moi le dire d'une manière différente? comment mettre cette "classe PreScoreCalculator (données: Seq [Int]) étend Caluclator" dans la carte?



1
votes

Vous ne devez pas appeler isInstanceOf & asInstanceOf manuellement, car cela jette essentiellement le compilateur.
Vous devriez utiliser la correspondance de modèle à la place:

opt match {
   case Some(c: PreScoreCalculator) => calculationController.calculate(c)
   ... // Other calculators.
   case None => println("Calculator not found.")
}

Remarque: c'est fondamentalement le même Ichoran et j'ai déjà dit dans gitter, je laisse juste ceci ici pour l'enregistrement .


4 commentaires

Miguel Mejia Suarez Merci beaucoup pour plus de clarté, si mon PreScoreCalculator prend un constructeur à savoir PreScoreCalculator (données: Seq [Int]) comment le gérer, dans le scénario ci-dessus?


@Miguel Mejia Suarez Pouvez-vous s'il vous plaît recommander un bon livre pour apprendre la conception d'applications scala et les meilleures pratiques?


@Shyam Pouvez-vous préciser cela s'il vous plaît? Avez-vous également besoin d'extraire cette Seq ? PS: Pouvez-vous modifier le code des calculatrices, ou celles-ci sont hors de votre contrôle?


@Shyam Techniquement parlant, SO n'est pas un endroit pour demander des recommandations de livres / cours ... mais, comme c'est un commentaire et non une question en soi, je suppose que ce n'est pas trop mal. Bien sûr, tout le monde pensera différemment, mais j'ai beaucoup aimé "Programming in Scala" (Book) & "Functional Programming in Scala" (Spécialisation Coursera) pour commencer. Et après un certain temps, (la plupart des gens recommandent un an d’expérience) commencer à en apprendre davantage sur la PF «Scala with Cats» est un excellent début.