2010-10-20 11 views
8

No sé a qué llamar mis "setters" en objetos inmutables?Convención de nombres Scala para "setters" en objetos inmutables

para una persona objeto mutable, los emisores funcionan así:

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) 

Esto es todo muy bien, pero lo que si la persona es inmutable?

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) 

¿Cómo debería llamarse whatHereName?

EDIT: que necesito para poner cosas en el método "setter", así:

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

El código real es mucho más grande que esto, por lo que una simple llamada al método copy no lo hará hacer.

EDIT 2:

Ya que hay muchos comentarios sobre mi ejemplo falsa (que es incorrecto) que será mejor que dé la link a la clase real (Avatar).

Los métodos "setter" no sé cómo llamarlo son updateStrength, updateWisdom ... pero probablemente va a cambiar eso a withStrength pronto ..

+3

¿Has echado un vistazo a http://davetron5000.github.com/scala-style/ScalaStyleGuide.pdf 3.4.1 Accessors/Mutators – oluies

+0

+100 @oluies GRACIAS! Este documento será mi biblia a partir de ahora. –

+0

Entonces, se conformó con 'con' :) Se ve bastante bien cuando la actualización del estado del objeto es lo único que sucede aquí. Pero, ¿y si esta acción de 'actualización' tiene un efecto secundario? Digamos que es un objeto ActiveRecord inmutable, y el estado de la base de datos 'muttator' devuelve una nueva instancia inmutable. ¿Tiene "con" un aspecto lógico también en este caso? ¿Qué piensas? – tuxSlayer

Respuesta

12

me gusta la forma JodaTime. eso sería con Name.

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

más ejemplos JodaTime: http://joda-time.sourceforge.net/

+0

Cosa genial. Es solo que "con" me hace pensar en la palabra clave with mixin. –

+0

Todos votan por "con", por lo que "con" lo es. –

10

clases de caso Scala han autogenerado método copia para este propósito. Se utiliza la siguiente manera:

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

+0

El método "setter" probablemente debería usar el método de copia internamente. Pero el método "setter" podría hacer algo más que establecer el valor, podría incluir lógica que valide el nuevo nombre. –

+0

Ha preguntado acerca de la convención, por lo que el método ampliamente utilizado es un buen ejemplo de cómo se puede hacer. Puede escribir su propio método de copia con su propia validación y les resultará familiar a quienes usan clases de casos. –

+0

Te veo apuntar. –

2

adición a la respuesta Oleg, podría escribir la clase como esta:

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

que usaría así:

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

Usando el método de copia como arriba es posible, pero en su caso simple solo usaría:

val p2 = Person("Pelle") 

Los métodos de copia mostrar sus fortalezas si tiene clases como:

case class Person(name: String, age: Int, email: EMail, pets: List[Pet] = List()) 
val joe = Person("Joe", 41, EMail("[email protected]")) 
val joeAfterHisNextBirthday = joe.copy(age=42) 
+0

Gracias @soc, pero esto no es realmente lo que estoy buscando. Mi ejemplo anterior es una versión mucho más simplificada del problema real. En mi ejemplo real, necesito un método tipo "setter", que envuelve el método de copia. Y la pregunta es: ¿Cómo debería llamarse? –

1

Por el momento estoy usando update<Field> convención de nombre para todos "colocador" -como métodos sobre los objetos inmutables.

No puedo usar set<Field> ya que me recuerda demasiado a los setters mutables en Java.

¿Qué opina de utilizar update<Field> para todos los métodos que devuelven una instancia nueva de la misma identidad que la instancia actual?

+1

Eso suena bien, aunque prefiero un un poquito. – soc

+1

Si está siguiendo otras convenciones de Scala (especialmente con la biblioteca de colecciones), entonces debería preferir 'actualizar' a 'actualizar'. 'actualización' todavía sugiere una operación de mutación. Habiendo dicho todo eso, todavía estoy a favor de 'con' –

+0

Bueno, entonces "con" es! Gracias chicos. –

4

Si necesita realizar la validación, etc. al 'modificar' un campo, entonces ¿por qué debería ser diferente de la validación cuando crea el objeto?

En este caso, puede colocar la lógica necesaria de validación/error en el constructor de una clase de caso, y esto se usará siempre que se cree una nueva instancia mediante el método copy.

+0

Tiene la razón @Kevin, pero el ejemplo anterior no es para nada mi verdadero código (lo siento). En mi código, todos los "setters" no están haciendo la validación, están llamando a un método de utilidad común que se ocupa de la creación de instancias. En mi código no puedo usar copy porque tengo que mezclar rasgos. –

+0

@Kevin Actualicé la pregunta con un enlace al código real. Es un objeto complejo e inmutable. Si tienes tiempo para mirar, me alegraré. –

+1

Esas mezclas te causarán más dolor con el paso del tiempo. Debería estar favoreciendo la composición en lugar de la herencia aquí; Tu código parece decir que un Avatar es una Profesión y es una Raza, esto es falso, un Avatar tiene una Profesión y tiene una Raza. Codifique los conceptos fundamentales correctamente y todo lo demás debería encajar de forma mucho más fácil y natural. –

3

Puede definir un solo método para eso. De cualquier copy, o, en caso de que ya es una clase de caso, with:

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

EDITAR

El método copy en el ejemplo enlazado debe tener este aspecto:

// 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(...) 
} 
+0

Actualicé la pregunta con un enlace al código real. Es un objeto complejo e inmutable. –

+0

@olle ver edición. –

+0

Gracias por ayudarme. Ahora veo que la estrategia de copia funciona para mi código. –

0

Aunque las respuestas anteriores resuelven el problema, me gustaría compartir cómo trato con objetos inmutables (que es solo azúcar sintáctico).

Para tener una sintaxis más clara (IMHO) Implemento el método apply en clases inmutables, devolviendo el resultado del método copy en las clases de casos y una nueva instancia cuando es una clase normal. es decir:

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

Esto hace que el método "mutador" sea el método predeterminado para cualquier instancia de esa clase.

Cuestiones relacionadas