Соглашение об именах Scala для "сеттеров" на неизменяемых объектах - PullRequest
8 голосов
/ 20 октября 2010

Не знаю, как назвать мои «сеттеры» на неизменяемых объектах?

Для изменяемого объекта Person сеттеры работают так:

class Person(private var _name: String) {
  def name = "Mr " + _name
  def name_=(newName: String) {
    _name = newName
  }
}

val p = new Person("Olle")
println("Hi "+ p.name)
p.name = "Pelle"
println("Hi "+ p.name)

Это все хорошо, но что, если Персона неизменна?

class Person(private val _name: String) {
  def name = "Mr " + _name
  def whatHereName(newName: String): Person = new Person(newName)
}

val p = new Person("Olle")
println("Hi "+ p.name)
val p2 = p.whatHereName("Pelle")
println("Hi "+ p2.name)

Как назвать whatHereName? 1010 *

EDIT: Мне нужно поместить вещи в метод "setter", например так:

class Person(private val _name: String) {
  def name = "Mr " + _name
  def whatHereName(newName: String): Person = {
    if(name.length > 3)
      new Person(newName.capitalize)
    else
      throw new Exception("Invalid new name")
  }
}

Реальный код намного больше этого, поэтому простой вызов метода copy не подойдет.

РЕДАКТИРОВАТЬ 2:

Поскольку к моему фальшивому примеру так много комментариев (что оно неверно), лучше дать вам ссылку на реальный класс (Avatar).

Методы "setter", которые я не знаю, что вызывать, это updateStrength, updateWisdom ... но я, вероятно, скоро изменю это на withStrength ..

Ответы [ 7 ]

13 голосов
/ 20 октября 2010

Мне нравится путь йодатима.это было бы с Name.

val p = new Person("Olle")
val p2 = p.withName("kalle");

больше примеров йодатимов: http://joda -time.sourceforge.net /

10 голосов
/ 20 октября 2010

Классы дел Scala имеют автоматически сгенерированный метод copy для этой цели. Используется так: val p2 = p.copy(name = "Pelle")

4 голосов
/ 20 октября 2010

Если вам нужно выполнить проверку и т. Д. При «изменении» поля, то почему это должно отличаться от проверки при первом создании объекта ?

В этом случае вы можете поместить необходимую логику проверки / выдачи ошибок в конструктор класса case, и это будет использоваться всякий раз, когда новый экземпляр создается с помощью метода copy.

3 голосов
/ 20 октября 2010

Вы можете определить один метод для этого. Либо copy, либо, если это уже класс наблюдения, with:

class Person(private val _name: String) {
  def name = "Mr " + _name
  def copy(name: String = _name): Person = new Person(name)
}

EDIT

Метод copy в связанном примере должен выглядеть следующим образом:

// Setters
def copy(strength: Int = features.strength,
         wisdom: Int = features.wisdom,
         charisma: Int = features.charisma,
         hitpoints: Int = features.hitpoints): Avatar = {
  if (hitpoints != features.hitpoints)
    println("setHitpoints() old value: " + features.hitpoints + ", new value: " + hitpoints)

  if (hitpoints > 0) 
    updateCreatureFeature(
      features.copy(strength = strength,
                    wisdom = wisdom,
                    charisma = charisma,
                    hitpoints = hitpoints))
  else
    throw new DeathException(name + " died!")

  // Alternate coding (depend on thrown exception on "check"):
  // check(strength, wisdom, charisma, hitpoints)
  // updateCreateFeature(...)
}
2 голосов
/ 20 октября 2010

Добавляя к Олегу ответ, вы бы написали класс так:

case class Person(name: String) //That's all!

Вы бы использовали это так:

val p = Person("Olle") // No "new" necessary
println("Hi" + p.name)
val p2 = p.copy(name="Pelle")
println("Hi" + p2.name)    

Возможно использование метода копирования, как описано выше, но в вашем простом случае я бы просто использовал:

val p2 = Person("Pelle")

Методы копирования показывают свои сильные стороны, если у вас есть такие классы, как:

case class Person(name: String, age: Int, email: EMail, pets: List[Pet] = List())
val joe = Person("Joe", 41, EMail("joe@example.com"))
val joeAfterHisNextBirthday = joe.copy(age=42)
1 голос
/ 20 октября 2010

На данный момент я использую update<Field> соглашение об именах для всех "setter" -подобных методов на неизменяемых объектах.

Я не могу использовать set<Field>, поскольку это слишком напоминает изменяемые сеттеры в Java.

Как вы относитесь к использованию update<Field> для всех методов, которые возвращают новый экземпляр с той же идентичностью, что и текущий экземпляр?

0 голосов
/ 27 декабря 2013

Хотя предыдущие ответы решили проблему, я хотел бы поделиться тем, как я имею дело с неизменяемыми объектами (которые являются только синтаксическим сахаром).

Чтобы иметь более четкий синтаксис (IMHO), я реализую метод apply в неизменяемых классах, возвращая результат метода copy в классах case и новый экземпляр, когда это обычный класс. а именно:

import java.util.Date

class Tournament (val name: String, val start: Date) {
  /* With case class
  def apply (name: String = this.name, start: Date = this.start) =
    copy (name, start)
  */

  def apply (name: String = this.name, start: Date = this.start) =
    new Tournament (name, start)

  override def toString () = s"${name} at ${start}"
}

object Main extends App {
  val tour = new Tournament ("Euroleague", new Date)
  val tour2 = tour (name = tour.name + " 2014")
  println (tour)
  println (tour2)
}

Это делает метод «мутатор» методом по умолчанию для любого экземпляра этого класса.

...