¿Son los getters y setters un diseño pobre? Consejo contradictorio visto [duplicado]


Esta pregunta ya tiene una respuesta aquí:

Actualmente estoy trabajando en un juego simple en Java con varios modos diferentes. He extendido una clase de juego principal para poner la lógica principal dentro de las otras clases. A pesar de esto, la clase de juego principal sigue siendo bastante fuerte.

Después de tomar un vistazo rápido a mi código la mayoría de ellos fue Getters y Setters (60%) en comparación con el resto que es realmente necesario para la lógica del juego.

Un par de búsquedas en Google han afirmado que los Getters y Setters son malos, mientras que otros han afirmado que son necesarios para la buena práctica de OO y grandes programas.

Entonces, ¿qué debo hacer? ¿Cuál debería ser? ¿Debo cambiar mis Getters y Setters para mis variables privadas, o debo seguir con ellos?

Author: chŝdk, 2009-02-19

16 answers

También existe el punto de vista de que la mayoría de las veces, el uso de setters todavía rompe la encapsulación al permitirle establecer valores que no tienen sentido. Como un ejemplo muy obvio, si usted tiene un contador de puntuación en el juego que solo sube, en lugar de

// Game
private int score;
public void setScore(int score) { this.score = score; }
public int getScore() { return score; }
// Usage
game.setScore(game.getScore() + ENEMY_DESTROYED_SCORE);

Debe ser

// Game
private int score;
public int getScore() { return score; }
public void addScore(int delta) { score += delta; }
// Usage
game.addScore(ENEMY_DESTROYED_SCORE);

Este es quizás un ejemplo un poco fácil. Lo que estoy tratando de decir es que discutir getter / setters vs campos públicos a menudo oscurece problemas más grandes con los objetos manipulando a los demás estado interno de una manera íntima y por lo tanto estar demasiado estrechamente acoplado.

La idea es crear métodos que hagan directamente las cosas que quieres hacer. Un ejemplo sería cómo establecer el estado "vivo" de los enemigos. Usted podría estar tentado a tener un método setAlive (booleano vivo). En su lugar, usted debe tener:

private boolean alive = true;
public boolean isAlive() { return alive; }
public void kill() { alive = false; }

La razón de esto es que si cambia la implementación de que las cosas ya no tienen un valor booleano "vivo" sino más bien un valor de "puntos de vida", puede cambiar eso sin romper el contrato de los dos métodos que escribió anteriormente:

private int hp; // Set in constructor.
public boolean isAlive() { return hp > 0; } // Same method signature.
public void kill() { hp = 0; } // Same method signature.
public void damage(int damage) { hp -= damage; }
 340
Author: Zarkonnen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 13:03:56
  • Muy malo: campos públicos.
  • Algo malo: Getters y setters donde no son necesarios.
  • Bueno: Getters y setters solo donde realmente son necesarios - hacer que el tipo exponga un comportamiento "más grande" que sucede a usar su estado, en lugar de solo tratar el tipo como un repositorio de estado para ser manipulado por otros tipos.

Sin embargo, realmente depende de la situación - a veces realmente haces solo quieres un objeto de datos tonto.

 177
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 12:36:07

Usted ya ha tenido un montón de buenas respuestas sobre esto, así que voy a dar mis dos centavos. Los getters y setters son muy, muy malvados. Esencialmente le permiten fingir ocultar las funciones internas de su objeto cuando la mayoría de las veces todo lo que ha hecho es arrojado en código redundante que no hace nada para ocultar el estado interno. Para un POJO simple, no hay razón por la que getName () y setName () no puedan ser reemplazados con obj.name = "Tom".

Si la llamada al método simplemente reemplaza la asignación, entonces todo lo que has ganado prefiriendo la llamada al método es código hinchado. Desafortunadamente, el lenguaje ha consagrado el uso de getters y setters en la especificación JavaBeans, por lo que los programadores de Java se ven obligados a usarlos, incluso cuando hacerlo no tiene ningún sentido.

Afortunadamente, Eclipse (y probablemente otros IDE también) le permite generarlos automáticamente. Y para un proyecto divertido, una vez construí un generador de código para ellos en XSLT. Pero si hay una cosa que me desharía de en Java, es la dependencia excesiva de getters y setters.

 42
Author: rtperson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-20 19:23:08

Los getters y setters refuerzan el concepto de encapsulación en la programación orientada a objetos.

Al tener los estados del objeto ocultos del mundo exterior, el objeto está verdaderamente a cargo de sí mismo, y no puede ser alterado de maneras que no son intencionadas. Las únicas formas en que el objeto puede ser manipulado son a través de métodos públicos expuestos, como getters y setters.

Hay algunas ventajas para tener getters y setters:

1. Permitir cambios futuros sin modificación al código que usa la clase modificada.

Una de las grandes ventajas de usar un getter y setter es que una vez que los métodos públicos están definidos y llega un momento en que la implementación subyacente necesita ser cambiada (por ejemplo, encontrar un error que necesita ser corregido, usar un algoritmo diferente para mejorar el rendimiento, etc.).), al hacer que los getters y setters sean la única manera de manipular el objeto, permitirá que el código existente no se rompa, y trabaje como se espera incluso después del cambio.

Por ejemplo, digamos que hay un método setValue que establece la variable privada value en un objeto:

public void setValue(int value)
{
    this.value = value;
}

Pero luego, hubo un nuevo requisito que necesitaba mantener un registro del número de veces que value se cambió. Con el setter en su lugar, el cambio es bastante trivial:

public void setValue(int value)
{
    this.value = value;
    count++;
}

Si el campo value fuera público, no hay una manera fácil de volver más tarde y agregar un contador que realice un seguimiento del número de veces que el valor fue cambiar. Por lo tanto, tener getters y setters es una forma de "preparar para el futuro" la clase para los cambios que puedan venir más tarde.

2. Imponer los medios por los cuales el objeto puede ser manipulado.

Otra forma en que los getters y setters son útiles es imponer las formas en que el objeto puede ser manipulado, por lo tanto, el objeto tiene el control de su propio estado. Con las variables públicas de un objeto expuesto, se puede corromper fácilmente.

Por ejemplo, un objeto ImmutableArray contiene una matriz int llamada myArray. Si el array fuera un campo público, simplemente no será inmutable:

ImmutableArray a = new ImmutableArray();
int[] b = a.myArray;
b[0] = 10;      // Oops, the ImmutableArray a's contents have been changed.

Para implementar un array verdaderamente inmutable, se debe escribir un getter para el array (método getArray) para que devuelva una copia de su array:

public int[] getArray()
{
    return myArray.clone();
}

, E incluso si ocurre lo siguiente:

ImmutableArray a = new ImmutableArray();
int[] b = a.getArray();
b[0] = 10;      // No problem, only the copy of the array is affected.

El ImmutableArray es de hecho inmutable. Exponer las variables de un objeto permitirá que sea manipulado de maneras que no están previstas, pero solo exponiendo ciertas maneras (getters y setters), el objeto puede ser manipulado de la manera deseada.

Supongo que tener getters y setters sería más importante para las clases que son parte de una API que va a ser utilizada por otros, ya que permite mantener la API intacta y sin cambios al tiempo que permite cambios en la implementación subyacente.

Con todas las ventajas de getters y setters dicho, si el getter está simplemente devolviendo el valor de la variable privada y el setter está simplemente aceptando un valor y asignándolo a una variable privada, parece que los getters y setter son simplemente extraños y realmente un desperdicio. Si la clase va a ser solo para uso interno por una aplicación que no va a ser utilizada por otros, usar getters y setters extensivamente puede no ser tan importante como cuando se escribe una API pública.

 27
Author: coobird,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 13:37:02

Son absolutamente malvados.

@coobird desafortunadamente no "imponen el concepto de encapsulación", todo lo que hacen es hacerte pensar que estás encapsulando datos cuando de hecho estás exponiendo datos a través de una propiedad con delirios de grandeza de método. Cualquier cosa que un getter / setter hace un campo público lo hace mejor.

Primero, si desea datos públicos, hágalos públicos, deshágase de los métodos getter y setter para reducir el número de métodos que el cliente tiene que recorrer y hacer es cognitivamente más simple para el cliente cambiar su valor por ejemplo.

object.field = value;

En lugar de la más cognitivamente intensa

object.setField(value);

Donde el cliente ahora debe comprobar el método getter/setter para ver si tiene algún efecto secundario.

En segundo lugar, si realmente necesita hacer algo más en el método, ¿por qué llamarlo un método get/set cuando tiene más responsabilidades que simplemente obtener o configurar? O bien seguir el SRP o llamar al método algo que realmente le dice lo que el todo método hace como los ejemplos de Zarkonnen que mencionó por ejemplo.

public void kill(){
    isAlive = false;
    removeFromWorld(this);
}

En lugar de

public void setAlive(boolean isAlive){
    this.isAlive = isAlive;
    if (isAlive)
        addToWorld(this);
    else
        removeFromWorld(this);
}

¿Dónde le dice el método setAlive(booleano) al cliente que como efecto secundario eliminará el objeto del mundo? ¿Por qué el cliente debería tener algún conocimiento sobre el campo isAlive? Además, ¿qué sucede cuando el objeto se vuelve a agregar al mundo, debe ser reinicializado? ¿por qué le importaría al cliente algo de eso?

En mi humilde opinión la moral es nombrar métodos para decir exactamente lo que hacen, seguir el SRP y deshacerse de getters / setters. Si hay problemas sin getters/setters, dile a los objetos que hagan su propio trabajo sucio dentro de su propia clase en lugar de intentar hacer cosas con ellos en otras clases.

Aquí termina mi diatriba, lo siento por eso;)

 24
Author: nathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-08 11:03:49

Es una pendiente resbaladiza.

Un objeto de transferencia simple (u objeto de parámetro) puede tener el único propósito de mantener algunos campos y proporcionar sus valores a pedido. Sin embargo, incluso en ese caso degenerado se podría argumentar que el objeto debe ser inmutable configured configurado en el constructor y exponiendo solo get... método.

También está el caso de una clase que expone algunas "perillas de control"; la interfaz de usuario de la radio de su automóvil probablemente se puede entender como exponer algo como getVolume, setVolume, getChannel, y setChannel, pero su funcionalidad real es recibir señales y emitir sonido. Pero esas perillas no exponen muchos detalles de implementación; no sabes por esas características de la interfaz si la radio es transistores, en su mayoría software o tubos de vacío.

Cuanto más comience a pensar en un objeto como un participante activo en una tarea de dominio de problemas, más pensará en términos de pedirle que haga algo en lugar de pedirle que le diga sobre su estado interno, o pidiéndole sus datos para que otro código pueda hacer algo con esos valores.

So... ¿"malvado"? En realidad no. Pero cada vez que te inclinas a poner un valor y exponer ambos get... y set... métodos sobre ese valor, pregúntese por qué, y cuál es la responsabilidad de ese objeto realmente. Si la única respuesta que puedes darte a ti mismo es, "Mantener este valor para mí", entonces tal vez algo además de OO está pasando aquí.

 19
Author: joel.neely,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 13:02:57

Su clase de juego probablemente esté siguiendo el objeto dios antipatrón si expone tantas variables. No hay nada malo con los getters y setters (aunque su verbosidad en Java puede ser un poco molesta); en una aplicación bien diseñada donde cada clase tiene una funcionalidad claramente separada, no necesitarás docenas de ellos en una sola clase.

Edit: Si el punto principal para los getters y setters es "configurar" la clase de juego (entiendo su comentario de esa manera), entonces probablemente no necesite los getters (está perfectamente bien que una clase acceda a sus propias variables privadas sin usar métodos get), y probablemente pueda colapsar muchos de los setters en "setters de grupo" que establecen varias variables que pertenecen conceptualmente juntas.

 15
Author: Michael Borgwardt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 12:59:12

Mi opinión es que los getters y setters son un requisito para buenos programas. Apégate a ellos, pero no escribas getters/setters innecesarios - no siempre es necesario tratar directamente con todas las variables.

 11
Author: Joonas Pulakka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 12:36:42

La presencia de getter y setters tiende a indicar (un "olor" si te gusta ese tipo de lenguaje de la escuela primaria) que hay un problema de diseño. Los getters y setters triviales apenas se distinguen de los campos públicos. Por lo general, el código que opera en los datos estará en una encapsulación de clase pobre diferente, y lo que se espera de los programadores no está a gusto con OO.

En algunos casos los getters y setters están bien. Pero como regla un tipo con ambos getters y setters indica problemas de diseño. Los getters trabajan para la inmutabilidad; los setters trabajan para "tell don't ask". Tanto la inmutabilidad como" tell don't ask " son buenas opciones de diseño, siempre y cuando no se apliquen en un estilo superpuesto.

 11
Author: Tom Hawtin - tackline,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 12:56:50

Realmente no creo que sean malvados. Pero me encantaría vivir en un mundo donde nunca tuve que usarlos a menos que realmente necesitaba.

Un ejemplo que leí arriba fue future-proofing su código. Por ejemplo:

public void setValue(int value)
{
    this.value = value;
}

Luego, los requisitos cambian y debe realizar un seguimiento de cuántas veces se estableció el valor.

Así que:

public void setValue(int value)
{
    this.value = value;
    count++;
}

, Esto es hermoso. Lo entiendo. Sin embargo, en Ruby, ¿lo siguiente no serviría para el mismo propósito?

someobject.my_value = 100

Más tarde, debe realizar un seguimiento del número de times my_value fue establecido. Bueno, entonces, ¿no podrías simplemente anular el setter LUEGO y solo LUEGO?

def my_value=(value)
    @my_value = value
    @count++
end

Estoy a favor del código hermoso, pero tengo que admitir que mirar a través de las montañas de clases de Java que tenemos y ver literalmente miles y miles de líneas de código que NO son MÁS que getter/setters básicos es feo y molesto.

Cuando estaba desarrollando en C # a tiempo completo, usamos propiedades públicas todo el tiempo e hicimos getters/setters personalizados solo cuando necesario. Funcionó como un encanto y no rompió nada.

 9
Author: cbmeeks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-03 16:20:53

Como siempre, la única respuesta es: depende. Si eres el único perón que toca el código, puedes hacer cualquier cosa con la que te sientas cómodo, incluyendo tomar atajos.

Uno de los beneficios de usar setters es que las comprobaciones deben realizarse en una sola ubicación en su código.

Es posible que desee prestar más atención a lo que realmente se obtiene y establece mediante estos métodos. Si los está utilizando para proporcionar acceso a valores constantes, probablemente esté mejor si usa constante.

 4
Author: Jeroen van Bergen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 12:38:21

Esto depende del lenguaje de programación en cuestión. Su pregunta se enmarca en el contexto de Java, donde parece que los getters y setters son generalmente considerados como algo bueno.

Por el contrario, en el mundo de Python, generalmente se consideran un estilo malo: agregan líneas al código sin agregar funcionalidad. Cuando los programadores de Python lo necesitan, pueden usar metaprogramación para capturar la obtención y/o configuración de atributos de objeto.

En Java (al menos el versión de Java que aprendí un poco hace una década), que no era posible. Por lo tanto, en Java generalmente es mejor usar getters y setters religiosamente, de modo que si lo necesita, puede anular el acceso a las variables.

(Esto no hace que Python sea necesariamente mejor que Java, solo diferente.)

 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 12:53:40

Solo para tu información: Además de todas las excelentes respuestas en este hilo, recuerda que de todas las razones por las que se te pueden ocurrir a favor o en contra de los getters/setters, el rendimiento no es uno (como algunos podrían creer). La JVM es lo suficientemente inteligente como para insertar getters/setters triviales (incluso los que no sonfinal, siempre y cuando en realidad no se anulen).

 2
Author: gustafc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 12:59:03

Es posible que desee reemplazar algunas de sus clases por clases de valor. Esto le permitirá eliminar el getter y evitar problemas cuando el contenido se cambia desde debajo de usted.

 1
Author: David S.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 12:37:24

Si necesita acceso externo a valores individuales de campos, utilice getters y/ o setters. Si no, no lo hagas. Nunca uses campos públicos. Es tan simple como eso! (Ok, nunca es que simple, pero es una buena regla general).

En general, también debe encontrar que necesita proporcionar un setter mucho menos a menudo que un getter, especialmente si está tratando de hacer que sus objetos sean inmutables, lo que es Bueno (pero no siempre la mejor opción), pero incluso si no.

 1
Author: philsquared,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 12:42:40

He estado programando en java hace unos meses, y he aprendido que debemos usar getters & setters solo cuando sea necesario para la aplicación

Diviértete:)

 0
Author: Giancarlo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 13:40:44