简体   繁体   English

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

[英]Scala naming convention for “setters” on immutable objects

I do not know what to call my "setters" on immutable objects? 我不知道在不可变对象上叫什么叫“setter”?

For a mutable object Person, setters work like this: 对于一个可变对象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)

This is all well and good, but what if Person is immutable? 这一切都很好,但如果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)

What should whatHereName be called? 我应该whatHereName叫?

EDIT: I need to put stuff in the "setter" method, like this: 编辑:我需要把东西放在“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")
  }
}

The real code is much bigger than this, so a simple call to the copy method will not do. 真正的代码比这大得多,所以对copy方法的简单调用是行不通的。

EDIT 2: 编辑2:

Since there are so many comments on my faked example (that it is incorrect) I better give you the link to the real class ( Avatar ). 由于我的伪造例子有很多评论(这是不正确的)我最好给你链接到真正的类( Avatar )。

The "setter" methods I don't know what to call are updateStrength , updateWisdom ... but I will probably change that to withStrength soon.. 我不知道该叫什么的“setter”方法是updateStrengthupdateWisdom ......但是我很快就会把它withStrength ..

I like the jodatime way. 我喜欢jodatime的方式。 that would be withName. 这将是withName。

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

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

Scala case classes have autogenerated method copy for this purpose. 为此,Scala案例类具有自动生成的方法副本 It's used like this: 它的使用方式如下:


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

If you need to perform validation, etc. when 'modifying' a field, then why should this be any different from validation when you first create the object ? 如果在“修改”字段时需要执行验证等,那么为什么在首次创建对象时这与验证有什么不同呢?

In this case, you can then put the necessary validation/error-throwing logic in the constructor of a case class, and this will be used whenever a new instance is created via the copy method. 在这种情况下,您可以将必要的验证/错误抛出逻辑放在案例类的构造函数中,只要通过copy方法创建新实例,就会使用此逻辑。

You could define a single method for that. 您可以为此定义一个方法。 Either copy , or, in case it is already a case class, with : 无论是copy ,或在情况下,它已经是一个案例类, with

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

EDIT 编辑

The copy method on the linked example should look like this: 链接示例上的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(...)
}

Adding to Oleg answer, you would write the class like this: 添加到Oleg的答案,你会写这样的类:

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

You would use it like this: 你会像这样使用它:

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

Using the copy method like above is possible, but in your simple case I would just use: 使用上面的复制方法是可能的,但在你的简单情况下我会使用:

val p2 = Person("Pelle")

The copy methods show their strengths if you have classes like: 如果你有类似的类,复制方法显示了它们的优势:

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)

As for now I am using update<Field> name convention for all "setter"-like methods on immutable objects. 至于现在,我对不可变对象的所有“setter”类方法使用update<Field>名称约定。

I can not use set<Field> since it reminds too much about the mutable setters in Java. 我不能使用set<Field>因为它提醒了Java中的可变setter。

How do you feel about using update<Field> for all methods that returns a new instance of the same identity as the current instance? 对于返回与当前实例具有相同标识的新实例的所有方法,您如何使用update<Field>

Though previous answers resolve the problem, I would like to share how I deal with immutable objects (which is only syntactic sugar). 虽然以前的答案解决了这个问题,但我想分享一下我如何处理不可变对象(这只是语法糖)。

To have a clearer syntax (IMHO) I implement the apply method in immutable classes, returning the result of the copy method in case classes and a new instance when it is a regular class. 为了有一个更清晰的语法(恕我直言),我在不可变类中实现apply方法,在case类中返回copy方法的结果,在它是常规类时返回一个新实例。 ie: 即:

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

This makes the "mutator" method the default method for any instance of that class. 这使得“mutator”方法成为该类的任何实例的默认方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM