[英]Scala naming convention for “setters” on immutable objects
我不知道在不可變對象上叫什么叫“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:
由於我的偽造例子有很多評論(這是不正確的)我最好給你鏈接到真正的類( Avatar
)。
我不知道該叫什么的“setter”方法是updateStrength
, updateWisdom
......但是我很快就會把它withStrength
..
我喜歡jodatime的方式。 這將是withName。
val p = new Person("Olle")
val p2 = p.withName("kalle");
更多jodatime示例: http ://joda-time.sourceforge.net/
for this purpose. 為此,Scala案例類具有自動生成的方法 。 它的使用方式如下:
val p2 = p.copy(name = "Pelle")
如果在“修改”字段時需要執行驗證等,那么為什么在首次創建對象時這與驗證有什么不同呢?
在這種情況下,您可以將必要的驗證/錯誤拋出邏輯放在案例類的構造函數中,只要通過copy
方法創建新實例,就會使用此邏輯。
您可以為此定義一個方法。 無論是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(...)
}
添加到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)
至於現在,我對不可變對象的所有“setter”類方法使用update<Field>
名稱約定。
我不能使用set<Field>
因為它提醒了Java中的可變setter。
對於返回與當前實例具有相同標識的新實例的所有方法,您如何使用update<Field>
?
雖然以前的答案解決了這個問題,但我想分享一下我如何處理不可變對象(這只是語法糖)。
為了有一個更清晰的語法(恕我直言),我在不可變類中實現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”方法成為該類的任何實例的默認方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.