¿Deberían los métodos de una clase llamar a sus propios captadores y definidores?

51

Donde trabajo, veo muchas clases que hacen cosas como esta:

public class ClassThatCallsItsOwnGettersAndSetters {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void methodWithLogic() {
        setField("value");
        //do stuff
        String localField = getField();
        //do stuff with "localField"
    }
}

Si escribiera esto desde cero, habría escrito el methodWithLogic() así:

public class ClassThatUsesItsOwnFields {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void methodWithLogic() {
        field = "value";
        //do stuff            
        //do stuff with "field"
    }
}

Siento que cuando la clase llama a sus propios captadores y definidores, hace que el código sea más difícil de leer. Para mí, casi implica que la lógica compleja está ocurriendo en esa llamada de método, aunque en nuestro caso casi nunca lo es. Cuando estoy depurando un código desconocido, ¿quién puede decir que el error no es un efecto secundario en ese método? En otras palabras, me hace realizar muchos viajes secundarios en el camino de entender el código.

¿Hay beneficios para el primer método? ¿Es realmente mejor el primer método?

    
pregunta Daniel Kaplan 04.01.2013 - 21:20

9 respuestas

46

No diré cuál es mejor o peor, porque eso depende en parte de tu situación (en mi opinión). Pero tenga en cuenta que sus captadores y definidores pueden cambiar la implementación más adelante, y omitirlos omitirá esa lógica.

Por ejemplo, ¿qué sucede si agrega una marca "sucia" a algunos campos del configurador más adelante? Al llamar a sus configuradores en su código interno, establecerá la bandera sucia sin cambiar ningún otro código. En muchas situaciones, esto sería bueno.

    
respondido por el Matt S 04.01.2013 - 21:34
31

Llamar al setter directamente no es, en sí mismo, un problema. La pregunta realmente debería ser: ¿Por qué nuestro código tiene configuradores en todas partes?

Las clases mutables son un juego peligroso, particularmente cuando la clase en sí misma administra su propio estado. Considera cuántos de esos setters realmente necesitan existir. ¿Cuántos podrían establecerse en el constructor y luego quedar encapsulados completamente por la clase?

Si el campo debe ser configurable externamente, pregúntese si el método con lógica debería estar allí. ¿Es tu clase en sí realmente solo una clase de datos / estado? ¿Esta clase tiene más de una responsabilidad?

No me malinterpretes, habrá casos en los que esto está bien. No estoy diciendo que debas eliminar los establecedores en las clases con lógica por completo. Pero estos deberían ser la excepción, no la regla. Y, en esos pocos casos, debería ser obvio a cuál acceder directamente.

    
respondido por el pdr 04.01.2013 - 21:49
9

Sí, los métodos de su clase deben llamar a los captadores y configuradores. Todo el punto en escribir getters y setters es pruebas futuras. Podría hacer que cada propiedad sea un campo y exponer directamente los datos a los usuarios de la clase. La razón por la que creas los captadores y definidores no es necesariamente porque ahora hay una lógica compleja, sino que la interfaz no se rompa en el futuro si es necesario agregarla.

    
respondido por el Michael 04.01.2013 - 21:33
6

Para responder a sus preguntas en una palabra, sí.

Tener una llamada de clase a sus propios getters y setters agrega extensibilidad y proporciona una mejor base para el código futuro.

Di que tienes algo como esto:

public class Vehicle
{
    private int year;
    private String make;

    public Vehicle(int year, String make)
    {
        setYear(year);
        setMake(make);
    }

    public void setYear(int year)
    {
        this.year = year;
    }

    public void setMake(String make)
    {
        this.make = make;
    }
}

Es posible que llamar a los configuradores por año y hacer que actualmente no agregue ninguna funcionalidad, pero ¿qué sucede si desea agregar algo como validación de entrada a los definidores?

public class Vehicle
{
    private int year;
    private String make;

    public Vehicle(int year, String make)
    {
        setYear(year);
        setMake(make);
    }

    public void setYear(int year)
    {
        if(year > 0)
        {
            this.year = year;
        }
        else
        {
            System.out.println(year + " is not a valid year!");
        }
    }

    public void setMake(String make)
    {
        this.make = make;
    }
}
    
respondido por el Zach Latta 05.01.2013 - 08:48
5

Una cosa que no se ha mencionado es que los getter y set (como todos los métodos) son virtuales en Java. Esto agrega otra característica a usarlos siempre en su código. Otro usuario podría extender su clase, sobrescribiendo a sus captadores y configuradores. Su clase base usaría entonces los datos de la subclase en lugar de los propios. En un idioma en el que marca explícitamente las funciones virtuales, esto es mucho más práctico, ya que puede predecir y declarar con qué funciones se puede realizar. En Java, esto es algo que siempre tendrías que tener en cuenta. Si es el comportamiento deseado, usarlos en tu código es bueno, de lo contrario no tanto.

    
respondido por el Jonathan Henson 09.01.2013 - 15:30
3

Si está tratando de lograr algo que proporciona la interfaz pública, use los métodos de obtención / configuración.

Sin embargo, como propietario / desarrollador de la clase, se le permite acceder a las secciones privadas de su código (desde dentro de la clase, por supuesto), pero también es responsable de mitigar los peligros.

Entonces, tal vez tenga un captador que se repite en una lista interna y desea obtener el valor actual sin incrementar el iterador. En este caso, utilice la variable privada.

public class MyClass
{
    private int i;
    private List<string> list;
    public string getNextString()
    {
        i++;
        return list[i];
    }

    private void getString()
    {
        // Do not increment
        string currentString = list[i];

        // Increment
        string nextString = getNextString();
    }
}
    
respondido por el ConditionRacer 04.01.2013 - 21:46
1

Sí. Los captadores y los definidores representan el estado, así que dale la vuelta a esta pregunta: ¿quieres tener que hacer un seguimiento de las múltiples formas de cambiar el estado de un objeto de la misma manera, a menos que tengas que hacerlo?

Cuantas menos cosas tenga para realizar un seguimiento de lo mejor, es por eso que es más fácil tratar con objetos inmutables.

Considere, no hay nada que le impida tener tanto un campo público como un receptor / definidor público, pero ¿qué ganaría?

En ocasiones puede ser deseable o, incluso, ser necesario para acceder directamente al campo por una o más razones, por lo que no debe evitarlo. Pero realmente solo deberías hacerlo si hay un beneficio definido para hacerlo.

    
respondido por el jmoreno 05.01.2013 - 09:58
1

Ambos métodos tienen sus casos de uso. Como el establecedor público mantiene el valor del campo (y / o los valores enlazados) consistentes, debe usar el establecedor cuando la lógica de su método no interfiera con esta lógica de consistencia. Si acaba de configurar su "propiedad", use setter. Por otro lado, hay situaciones en las que se necesita acceso directo a algunos campos, por ejemplo, operaciones en masa con setter pesado u operaciones en las que el concepto de setter es demasiado simple.

Es tu responsabilidad mantener las cosas consistentes. Setter hace esto por definición, pero no puede cubrir casos complejos.

    
respondido por el Artur 05.01.2013 - 19:18
1

Yo diría que no ...

Si sus captadores / configuradores simplemente obtienen y configuran (sin inicialización perezosa, sin comprobaciones, etc.), entonces solo use sus variables. Si en el futuro cambia a sus captadores / establecedores, puede cambiar muy bien su methodWithLogic() (porque su clase está cambiando) y puede llamar a un captador / definidor en lugar de una asignación directa. Puede documentar esta llamada para el captador / configurador (ya que será extraño llamar a un captador / definidor cuando el resto de su código de clase esté usando la variable directamente).

La JVM integrará las llamadas frecuentes a los conserjes / preparadores. Por lo tanto, nunca es un problema de rendimiento. La ganancia de usar variables es la legibilidad y en mi humilde opinión, me gustaría ir por ella.

Espero que esto ayude ..

    
respondido por el Pravin Sonawane 09.01.2013 - 15:06

Lea otras preguntas en las etiquetas