Pregunta ¿Por qué usar getters y setters / accessors? [cerrado]


¿Cuál es la ventaja de utilizar getters y setters, que solo se obtienen y configuran, en lugar de simplemente usar campos públicos para esas variables?

Si getters y setters hacen algo más que el simple get / set, puedo resolver esto muy rápido, pero no estoy 100% claro sobre cómo:

public String foo;

es peor que:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

Mientras que el primero toma mucho menos código repetitivo.


1303
2017-10-14 18:20


origen


Respuestas:


En realidad hay muchas buenas razones considerar el uso de accesorios en lugar de exponer directamente los campos de una clase, más allá del argumento de la encapsulación y facilitar los cambios futuros.

Estas son algunas de las razones que conozco:

  • Encapsulación del comportamiento asociado con la obtención o configuración de la propiedad: esto permite que funciones adicionales (como la validación) se agreguen más fácilmente más adelante.
  • Ocultar la representación interna de la propiedad mientras expone una propiedad usando una representación alternativa.
  • Aislar su interfaz pública del cambio, permitiendo que la interfaz pública permanezca constante mientras la implementación cambia sin afectar a los consumidores existentes.
  • Controlar la semántica de la propiedad y la gestión de memoria (eliminación) de la propiedad, lo que es particularmente importante en entornos de memoria no administrados (como C ++ o Objective-C).
  • Proporcionar un punto de interceptación de depuración para cuando una propiedad cambia en tiempo de ejecución: la depuración cuando y donde una propiedad cambia a un valor particular puede ser bastante difícil sin esto en algunos idiomas.
  • Mejora de la interoperabilidad con bibliotecas que están diseñadas para operar contra getter / setters de propiedad - Mocking, Serialization y WPF vienen a la mente.
  • Permitir que los herederos cambien la semántica de cómo se comporta la propiedad y se expone anulando los métodos getter / setter.
  • Permitir que el getter / setter se transmita como expresiones lambda en lugar de valores.
  • Getters y setters pueden permitir diferentes niveles de acceso; por ejemplo, el get puede ser público, pero el conjunto podría estar protegido.

794
2017-10-14 18:47



Porque 2 semanas (meses, años) a partir de ahora cuando te das cuenta de que tu setter necesita hacer Más que simplemente establecer el valor, también te darás cuenta de que la propiedad se ha utilizado directamente en otras 238 clases :-)


389
2017-10-14 18:23



Un campo público no es peor que un par getter / setter que no hace nada excepto devolver el campo y asignarlo. Primero, está claro que (en la mayoría de los idiomas) no hay diferencia funcional. Cualquier diferencia debe estar en otros factores, como el mantenimiento o la legibilidad.

Una ventaja mencionada de los pares getter / setter, no lo es. Existe la afirmación de que puede cambiar la implementación y no es necesario recompilar a sus clientes. Supuestamente, los setters te permiten agregar funcionalidad como validación más adelante y tus clientes ni siquiera necesitan saber al respecto. Sin embargo, agregar validación a un colocador es un cambio en sus condiciones previas, una violación del contrato anterior, que fue, simplemente, "puedes poner cualquier cosa aquí, y puedes obtener lo mismo más tarde del comprador".

Entonces, ahora que rompió el contrato, cambiar cada archivo en la base del código es algo que debería querer hacer, no evitar. Si lo evita, está asumiendo que todo el código asumió que el contrato para esos métodos era diferente.

Si ese no debería ser el contrato, la interfaz permite a los clientes colocar el objeto en estados no válidos. Eso es exactamente lo opuesto a la encapsulación Si ese campo realmente no se puede configurar desde el principio, ¿por qué no se realizó la validación desde el principio?

Este mismo argumento se aplica a otras supuestas ventajas de estos pares de captador / intermediario de transferencia: si posteriormente decide cambiar el valor que se está configurando, está incumpliendo el contrato. Si anula la funcionalidad predeterminada en una clase derivada, de una manera que va más allá de algunas modificaciones inofensivas (como el registro u otro comportamiento no observable), está rompiendo el contrato de la clase base. Eso es una violación del Principio de Sustituibilidad de Liskov, que es visto como uno de los principios de OO.

Si una clase tiene estos getters y setters tontos para cada campo, entonces es una clase que no tiene invariantes en absoluto, sin contrato. ¿Es eso realmente un diseño orientado a objetos? Si toda la clase tiene esos getters y setters, es solo un titular de datos tonto, y los titulares de datos tontos deben parecerse a los titulares de datos tontos:

class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};

Agregar pares getter / setter pass-through a dicha clase no agrega ningún valor. Otras clases deberían proporcionar operaciones significativas, no solo operaciones que los campos ya proporcionan. Así es como puede definir y mantener invariantes útiles.

Cliente: "¿Qué puedo hacer con un objeto de esta clase?"
Diseñador: "Puedes leer y escribir varias variables".
Cliente: "Oh ... genial, ¿supongo?"

Hay razones para usar getters y setters, pero si esas razones no existen, hacer pares getter / setter en nombre de dioses de encapsulación falsa no es algo bueno. Las razones válidas para hacer getters o setters incluyen las cosas que se mencionan a menudo como los posibles cambios que puede realizar más adelante, como la validación o las diferentes representaciones internas. O tal vez el valor debe ser legible por los clientes, pero no se puede escribir (por ejemplo, leyendo el tamaño de un diccionario), por lo que un simple getter es una buena opción. Pero esas razones deberían estar ahí cuando elija, y no solo como algo potencial que pueda desear más adelante. Esta es una instancia de YAGNI (No vas a necesitarlo)


307
2017-08-24 10:55



Mucha gente habla sobre las ventajas de los captadores y establecedores, pero yo quiero hacer de abogado del diablo. En este momento estoy depurando un programa muy grande donde los programadores decidieron hacer todo getters y setters. Eso puede parecer agradable, pero es una pesadilla de ingeniería inversa.

Digamos que está mirando a través de cientos de líneas de código y se encuentra con esto:

person.name = "Joe";

Es un código maravillosamente simple hasta que te das cuenta de que es un setter. Ahora, sigue ese setter y descubre que también establece person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName, y llama a person.update (), que envía una consulta a la base de datos, etc. Oh, eso es donde estaba ocurriendo su pérdida de memoria

Comprender un fragmento de código local a primera vista es una propiedad importante de una buena legibilidad que los getters y setters tienden a romperse. Es por eso que trato de evitarlos cuando puedo, y minimizar lo que hacen cuando los uso.


75
2017-10-14 21:00



Hay muchas razones. Mi favorito es cuando necesitas cambiar el comportamiento o regular lo que puedes establecer en una variable. Por ejemplo, supongamos que tienes un método setSpeed ​​(int speed). Pero desea que solo pueda establecer una velocidad máxima de 100. Haría algo como:

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

Ahora, ¿qué pasa si en cualquier lugar de su código estuviera usando el campo público y luego se dio cuenta de que necesita el requisito anterior? Diviértete buscando cada uso del campo público en lugar de solo modificar tu setter.

Mis 2 centavos :)


43
2017-10-14 18:27



En un mundo orientado a objetos puro getters y setters es un terrible anti-patrón. Lee este artículo: Getters / Setters. Mal. Período. En pocas palabras, alientan a los programadores a pensar sobre objetos a partir de estructuras de datos, y este tipo de pensamiento es puramente de procedimiento (como en COBOL o C). En un lenguaje orientado a objetos no hay estructuras de datos, sino solo objetos que exponen el comportamiento (¡no atributos / propiedades!)

Puede encontrar más información sobre ellos en la Sección 3.5 de Objetos elegantes (mi libro sobre la programación orientada a objetos).


43
2017-09-23 16:39



Una ventaja de los accessors y mutators es que puedes realizar la validación.

Por ejemplo, si foo era público, podría configurarlo fácilmente null y luego alguien más podría tratar de invocar un método sobre el objeto. ¡Pero ya no está allí! Con un setFoo método, podría asegurar que foo nunca fue configurado para null.

Los adaptadores y mutadores también permiten la encapsulación: si no se supone que veas el valor una vez establecido (quizás esté establecido en el constructor y luego utilizado por los métodos, pero nunca se suponga que deba cambiarse), nunca lo habrá visto nadie. Pero si puede permitir que otras clases lo vean o lo modifiquen, puede proporcionar el acceso y / o mutador adecuado.


36
2017-10-14 18:25



Depende de tu idioma Ha etiquetado este "orientado a objetos" en lugar de "Java", por lo que me gustaría señalar que la respuesta de ChssPly76 depende del idioma. En Python, por ejemplo, no hay ninguna razón para usar getters y setters. Si necesita cambiar el comportamiento, puede usar una propiedad que envuelve un getter y un setter en el acceso de atributos básicos. Algo como esto:

class Simple(object):
   def _get_value(self):
       return self._value -1

   def _set_value(self, new_value):
       self._value = new_value + 1

   def _del_value(self):
       self.old_values.append(self._value)
       del self._value

   value = property(_get_value, _set_value, _del_value)

28
2017-10-14 18:32