2017-12-21 25 views
0

In meiner Code-Basis möchte ich Refraktor entfernt von vars. Die Code Grundstruktur folgt das Format:Scala: var zu Val - Redesign

class Animal { 
    var name : Option[String] = None 
    var owner : Option[String] = None 
} 

case class Dog(breed: String) extends Animal { 
    //Dog logic 
} 

Der Hauptgrund für diesen Entwurf ist, dass alle Informationen zur gleichen Zeit nicht zur Verfügung stehen.

Also, von service A, die eine json deserialisiert, erhalte ich eine Animal (entweder Animal, Dog)

val animal = new Animal 
animal.name = "My little animal" 

und dann

def update(animal: Animal) : Unit { 
    animal match { 
     case a : Animal => a.owner = Some("Joe") // call to service B 
     case _   => //handle dog 
    } 
} 

update(animal) 

Die Frage ist: Wie kann ich es neu gestalten kann vermeidbaren Zustand in Animal vermeiden?

  • eine copy Methode in Animal schreiben? Es gibt eine Reihe von Feldern, die einige Vortexer erzeugen können.

  • Zusammensetzung?

Herstellung der beiden Klassen case?

case class Animal (...) 
case class Dog(animal: Animal, breed: String) 

bearbeiten

  • Tier als trait

Ich brauche noch eine konkrete Umsetzung Animal, wie ich Dogs und Animals (die wirklich sind Animal und kein Subtyp haben)

  • Probleme mit Kopie

Die bei Klasse Kopiermethode gebaut, aktualisiert nicht die Werte der Animal Klasse. So werden Standardwerte verwendet - nicht was ich will. - Ja, es ist möglich, eine Fallklasse mit allen Feldern zu erstellen, aber ist es praktisch, wenn wir mehr als 100 Felder haben?

+1

Fallklassen enthalten eine Kopiermethode https://stackoverflow.com/questions/7249396/how-to-clone-a-case-class-instance-and-change-just-one-field-in-scala – ameer

Antwort

0

Sie könnten entwerfen dies als ADT (Abstract Data Type) wie folgt aus:

trait Animal { 
    def name: Option[String] 
    def owner: Option[String] 
} 

case class Dog(dog: Option[String] = None, owner: Option[String] = None) extends Animal 

Mit einer Fallklasse Sie die Kopiermethode standardmäßig haben!

+0

If 'Tier' ist ein' Merkmal' die Deserialisierung schafft kein 'Tier' – Bruno

+0

Ich bearbeite, indem ich die extend-Klausel in die Hundeklasse – sparkr

0

Eine gute Lösung könnte sein, einen Zug zu machen, die Animal Verhalten gibt an,

sealed trait Animal { 
    val name: Option[String] 
    val owner: Option[String] 
} 

und dann case class es machen Typkonstruktoren für Ihr Tier Instanzen zur Verfügung stellen.

case class Dog(name: Option[String], owner: Option[String]) extends Animal 

Jetzt update (changeOwner) einen Animal nehmen und eine andere Animal zurückkehren ebenfalls:

def changeOwner(animal: Animal): Animal = animal match { 
    case Dog(name, owner) => Dog(name, Some("Joe")) 
    case _ => animal 
} 

Und Sie werden es wie folgt verwenden:

val dog: Animal = Dog(Some("Doggie"), Some("Jack")) 
val newDog: Animal = changeOwner(dog) 

Auch aus dem Code :

case a : Animal => a.owner = Some("Joe") // call to service B 

Seien Sie vorsichtig, da die erste case Ihrer match alle Tiere und damit die anderen Fälle, zum Beispiel Ihre Dog Fall, wird nicht erreichbar sein.

+0

einfüge Ich bearbeite, warum' Merkmal Tier' mir nicht passt und die Nachteile von 'Kopie' – Bruno

Verwandte Themen