Оба упомянутых вами способа относятся к функциональной и объектно-ориентированной парадигмам соответственно. Если вы предпочитаете функциональную декомпозицию с абстрактным типом данных, который в Scala представлен классами case, выберите метод копирования. В моем случае использование мутаторов не является хорошей практикой, потому что это вернет вас к образу жизни Java / C # / C ++.
С другой стороны, создание класса случая ADT как
case class Person(name: String, age: String)
тогда более логично:
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
}
Но все же способ класса case более продуман.
И если вы пойдете дальше, к параллельному / параллельному программированию, вы увидите, что функциональная концепция с неизменяемым значением намного лучше, тогда пытаясь угадать, в каком состоянии сейчас находится ваш объект.
Обновить
Спасибо сению, забыл упомянуть две вещи.
Линзы
На самом базовом уровне линзы являются своего рода геттерами и сеттерами неизменяемых данных и выглядят так:
case class Lens[A,B](get: A => B, set: (A,B) => A) {
def apply(a: A) = get(a)
// ...
}
Вот и все. Линза - это объект, который содержит две функции: получение и установку. get принимает A и возвращает B. set принимает A и B и возвращает новый A. Легко видеть, что тип B является значением, содержащимся в A. Когда мы передаем экземпляр для get, мы возвращаем это значение. Когда мы передаем A и B для установки, мы обновляем значение B в A и возвращаем новый A, отражающий изменение. Для удобства get имеет псевдоним для применения. Есть хорошее введение в класс корпуса Scalaz Lens.
Записи
Это, конечно, из библиотеки shapeless и называется Records. Реализация расширяемых записей, смоделированных как HLists ассоциаций. Ключи кодируются с использованием одноэлементных типов и полностью определяют типы соответствующих им значений (например, из 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)
person
4lex1v
schedule
09.07.2013