Entrambi i modi che hai menzionato appartengono rispettivamente ai paradigmi funzionali e OO. Se si preferisce la scomposizione funzionale con il tipo di dati astratti, che, in Scala, è rappresentato da classi del caso, quindi scegliere il metodo di copia. L'uso dei mutatori non è una buona pratica nella mia opzione, perché ciò ti riporterà al modo di vita Java/C#/C++.
D'altra parte rendendo classe caso ADT come
case class Person(name: String, age: String)
è più conciso poi:
class Person(_name: String, _age: String) {
var name = _name
var age = _a
def changeName(newName: String): Unit = { name = newName }
// ... and so on
}
(non il migliore codice imperativo, può essere più breve, ma chiaro).
Di causa c'è un altro modo con mutatori, solo per restituire un nuovo oggetto per ogni chiamata:
class Person(val name: String,
val age: String) {
def changeName(newName: String): Unit = new Person(newName, age)
// ... and so on
}
Ma ancora modo caso di classe è più conciso.
E se andate oltre, alla programmazione simultanea/parallela, vedrete che il concetto funzionale con valore immutabile è molto meglio, quindi cercate di indovinare in quale stato il vostro oggetto è attualmente.
Aggiornamento
Grazie alla Senia, dimenticato di citare due cose.
Lenti
Al livello più elementare, le lenti sono una sorta di getter e setter per i dati immutabili e si presenta in questo modo:
case class Lens[A,B](get: A => B, set: (A,B) => A) {
def apply(a: A) = get(a)
// ...
}
che è. Un obiettivo è un oggetto che contiene due funzioni: ottenere e impostare. prende un A e restituisce un B. set prende un A e B e restituisce un nuovo A. È facile vedere che il tipo B è un valore contenuto in A. Quando passiamo un'istanza per ottenere restituiamo quel valore. Quando passiamo un A e un B per impostare aggiorniamo il valore B in A e restituiamo un nuovo A che riflette il cambiamento. Per praticità, l'applicazione è alias da applicare.C'è una buona intro per Scalaz Lens caso classe
Records
Questo, ofcause, proviene dalla biblioteca shapeless e chiamati Records. Un'implementazione di record estensibili modellati come HLists di associazioni. Le chiavi sono codificate utilizzando i tipi singleton e determinano completamente i tipi dei loro valori corrispondenti (ex github):
object author extends Field[String]
object title extends Field[String]
object price extends Field[Double]
object inPrint extends Field[Boolean]
val book =
(author -> "Benjamin Pierce") ::
(title -> "Types and Programming Languages") ::
(price -> 44.11) ::
HNil
// Read price field
val currentPrice = book.get(price) // Inferred type is Double
currentPrice == 44.11
// Update price field, relying on static type of currentPrice
val updated = book + (price -> (currentPrice+2.0))
// Add a new field
val extended = updated + (inPrint -> true)
Per ottenere le modifiche, è possibile utilizzare Event Sourcing. –