Оба способа, о которых вы упомянули, относятся к функциональным и OO-парадигмам соответственно. Если вы предпочитаете функциональную декомпозицию с абстрактным типом данных, который в Scala представлен классами case, то выберите метод копирования. Использование мутаторов не является хорошей практикой в моем варианте, потому что это вернет вас к жизни Java/C#/C++.
С другой стороны, делая ADT класс случай как
case class Person(name: String, age: String)
более consise тогда:
class Person(_name: String, _age: String) {
var name = _name
var age = _a
def changeName(newName: String): Unit = { name = newName }
// ... and so on
}
(не самый лучший императивный код, может быть короче, но понятно).
Из причины есть еще один способ с мутаторами, просто возвращает новый объект при каждом вызове:
class Person(val name: String,
val age: String) {
def changeName(newName: String): Unit = new Person(newName, age)
// ... and so on
}
Но все-таки случай класс путь более consise.
И если вы пойдете дальше, к параллельному/параллельному программированию, вы увидите, что функциональный концепт с неизменяемым значением намного лучше, а затем tring, чтобы угадать, в каком состоянии находится ваш объект.
Update
Благодаря Сеня, забыл упомянуть две вещи.
Линзы
На самом базовом уровне, линзы являются своим родом добытчиков и сеттеров для неизменных данных и выглядят следующим образом:
case class Lens[A,B](get: A => B, set: (A,B) => A) {
def apply(a: A) = get(a)
// ...
}
То есть. Объектив - это объект, который содержит две функции: get и set. get принимает A и возвращает B. set принимает A и B и возвращает новый A. Легко видеть, что тип B является значением, содержащимся в A. Когда мы передаем экземпляр, чтобы получить, мы возвращаем это значение. Когда мы передаем A и B для установки, мы обновляем значение B в A и возвращаем новый A, отражающий изменение. Для удобства get применяется с псевдонимом.Существует хороший intro для Scalaz объектив случая класса
Запись
Это один, ofcause, приходит из shapeless библиотеки и вызываемого Records. Реализация расширяемых записей, смоделированных как HLists ассоциаций. Ключи кодируются с использованием одноэлементных типов и полностью определяют типы их соответствующих значений (ex from 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)
Чтобы получить изменения, вы можете использовать Event Sourcing. –