Scala在不可变对象上为“setter”命名约定

时间:2010-10-20 09:44:29

标签: scala conventions

我不知道在不可变对象上叫什么叫“setter”?

对于可变对象Person,setter的工作方式如下:

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)

这一切都很好,但如果Person是不可变的呢?

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应该被叫什么?

修改 我需要把东西放在“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:

由于我的伪造示例有很多评论(这是不正确的)我最好给你link到真正的班级(Avatar)。

我不知道该调用的“setter”方法是updateStrengthupdateWisdom ...但我很快就会将其更改为withStrength ..

7 个答案:

答案 0 :(得分:13)

我喜欢jodatime的方式。这将是withName。

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

更多jodatime示例:http://joda-time.sourceforge.net/

答案 1 :(得分:10)

为此,Scala案例类具有自动生成的方法 copy 。它的使用方式如下:

val p2 = p.copy(name = "Pelle")

答案 2 :(得分:4)

如果您在“修改”某个字段时需要执行验证等,那么为什么这与首次创建对象时的验证有何不同

在这种情况下,您可以将必要的验证/错误抛出逻辑放在案例类的构造函数中,只要通过copy方法创建新实例,就会使用此逻辑。

答案 3 :(得分:3)

您可以为此定义一种方法。 copy,或者,如果已经是案例类,with

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

修改

链接示例上的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(...)
}

答案 4 :(得分:2)

添加到Oleg的答案,你会写这样的类:

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)

答案 5 :(得分:1)

至于现在,我对不可变对象的所有“setter”类方法使用update<Field>名称约定。

我不能使用set<Field>,因为它提醒了Java中可变的setter。

对于返回与当前实例具有相同标识的新实例的所有方法,您如何使用update<Field>

答案 6 :(得分:0)

虽然以前的答案解决了这个问题,但我想分享一下我如何处理不可变对象(这只是语法糖)。

要有更清晰的语法(恕我直言),我在不可变类中实现apply方法,在case类中返回copy方法的结果,在常规类时返回新实例。即:

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)
}

这使得“mutator”方法成为该类的任何实例的默认方法。