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


¿Cuál es la ventaja de usar getters y setters - que solo get y set - en lugar de simplemente usar campos públicos para esas variables?

Si los getters y setters están haciendo algo más que el simple get / set, puedo resolver esto muy rápidamente, 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.

Author: Tim Castelijns, 2009-10-14

30 answers

En realidad hay muchas buenas razones para considerar el uso de accesores en lugar de exponer directamente los campos de una clase, más allá del argumento de la encapsulación y hacer que los cambios futuros sean más fáciles.

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 la funcionalidad adicional (como la validación) se agregue más fácilmente más adelante.
  • Ocultando el representación interna de la propiedad mientras se expone una propiedad utilizando una representación alternativa.
  • Aislando 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 vida útil y la gestión de la memoria (disposición) de la propiedad, particularmente importante en entornos de memoria no administrados (como C++ u Objective - C).
  • Proporcionar una depuración punto de interceptación para cuando una propiedad cambia en tiempo de ejecución-depurar cuándo y dónde una propiedad cambió a un valor particular puede ser bastante difícil sin esto en algunos idiomas.
  • Interoperabilidad mejorada con bibliotecas que están diseñadas para operar contra getter/setters de propiedades: Me vienen a la mente la burla, la serialización y WPF.
  • Permitiendo a los herederos cambiar la semántica de cómo se comporta la propiedad y se expone al sobreescribir el getter / setter método.
  • Permitiendo que el getter/setter se pase como expresiones lambda en lugar de valores.
  • Los getters y setters pueden permitir diferentes niveles de acceso - por ejemplo, el get puede ser público, pero el set puede estar protegido.
 813
Author: LBushkin,
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
2013-10-24 06:25:37

Debido a que dentro de 2 semanas (meses, años) cuando te des 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: -)

 397
Author: ChssPly76,
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-10-14 18:23:19

Un campo público no es peor que un par getter/setter que no hace nada excepto devolver el campo y asignarle. En primer lugar, 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 a menudo mencionada de los pares getter/setter, no lo es. Hay esta afirmación de que puede cambiar la implementación y sus clientes no tienen que ser recompilados. Supuestamente, los setters te permiten agregar funcionalidad como la validación más adelante y sus clientes ni siquiera necesitan saberlo. Sin embargo, agregar validación a un setter es un cambio en sus precondiciones, una violación del contrato anterior, que era, simplemente, "puedes poner cualquier cosa aquí, y puedes obtener lo mismo más tarde del getter".

Entonces, ahora que rompiste el contrato, cambiar cada archivo en la base de código es algo que deberías querer hacer, no evitar. Si lo evitas estás haciendo la suposición que todo el código asumía que el contrato para esos métodos era diferente.

Si ese no debería haber sido el contrato, entonces la interfaz estaba permitiendo a los clientes poner el objeto en estados no válidos. Eso es exactamente lo contrario de encapsulación Si ese campo realmente no se podía establecer en nada desde el principio, ¿por qué no estaba la validación allí desde el principio?

Este mismo argumento se aplica a otras supuestas ventajas de estos pares getter/setter de paso a través: si más tarde decide cambiar el valor que se establece, estás rompiendo el contrato. Si anula la funcionalidad predeterminada en una clase derivada, de una manera más allá de unas pocas modificaciones inofensivas (como el registro u otro comportamiento no observable), está rompiendo el contrato de la clase base. Esto constituye una violación del Principio de sustituibilidad de Liskov, que se considera 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 todo caso, ningún contrato . ¿Es realmente un diseño orientado a objetos? Si todo lo que la clase tiene son esos getters y setters, es solo un titular de datos tonto, y los titulares de datos tontos deberían parecerse a los titulares de datos tontos:

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

Agregar pares getter/setter de paso a través a tal clase no agrega valor. Otras clases deben proporcionar operaciones significativas, no solo las operaciones que los campos ya proporcionan. Así es como puedes definir y mantener invariantes útiles.

Client: "¿Qué puedo hacer con un objeto de esta clase?"
Designer : "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 falsos no es algo bueno. Las razones válidas para hacer getters o setters incluyen las cosas que a menudo se mencionan como los cambios potenciales que puede hacer más adelante, como validación o diferentes representaciones internas. O tal vez el valor debe ser legible por los clientes, pero no escribible (por ejemplo, la lectura del tamaño de un diccionario), por lo que un getter simple es una buena opción. Pero esas razones deben estar ahí cuando usted toma la decisión, y no solo como una cosa potencial que usted puede querer más adelante. Este es un ejemplo de YAGNI (No Vas A Necesitarlo).

 313
Author: R. Martinho Fernandes,
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
2015-02-17 13:26:41

Mucha gente habla de las ventajas de los getters y setters, pero yo quiero jugar al abogado del diablo. Ahora mismo 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ás mirando a través de cientos de líneas de código y te encuentras con esto:

person.name = "Joe";

Es una pieza de código bellamente simple hasta que te das cuenta de que es un setter. Ahora, sigue setter y encuentra que también establece persona.Nombre, persona.Apellido, persona.isHuman, persona.hasReallyCommonFirstName, y llama a person.update(), que envía una consulta a la base de datos, etc. Ahí es donde estaba ocurriendo tu pérdida de memoria.

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

 76
Author: Kai,
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-10-14 21:00:47

En un mundo orientado a objetos puros getters y setters es un terrible anti-patrón. Lee este artículo: Getters/Setters. Mal. Punto . En pocas palabras, animan a los programadores a pensar en los objetos como en estructuras de datos, y este tipo de pensamiento es puramente procedimental (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 Elegant Objects (mi libro sobre programación orientada a objetos).

 45
Author: yegor256,
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
2017-03-13 20:33:38

Hay muchas razones. Mi favorito es cuando necesitas cambiar el comportamiento o regular lo que puedes establecer en una variable. Por ejemplo, digamos que tenía un método setSpeed (int speed). Pero quieres que sólo se puede establecer una velocidad máxima de 100. Usted haría algo como:

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

Ahora, ¿qué pasaría si en TODAS PARTES de su código estuviera utilizando el campo público y luego se diera cuenta de que necesita el requisito anterior? Diviértete cazando cada uso del campo público en lugar de solo modificando tu setter.

Mis 2 centavos:)

 43
Author: Peter D,
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-10-14 18:27:22

Una ventaja de los accesores y mutadores es que puede realizar la validación.

Por ejemplo, si foo fuera público, fácilmente podría configurarlo en null y luego alguien más podría intentar llamar a un método en el objeto. ¡Pero ya no está ahí! Con un método setFoo, pude asegurar que foo nunca se estableció en null.

Los accesores y los mutadores también permiten la encapsulación , si no se supone que vea el valor una vez establecido (tal vez esté establecido en el constructor y luego utilizado por métodos, pero nunca se supone que deben ser cambiados), nunca será visto por nadie. Pero si puede permitir que otras clases lo vean o lo cambien, puede proporcionar el accessor y/o mutador adecuado.

 36
Author: Thomas Owens,
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-10-14 18:25:11

Depende de tu idioma. Has etiquetado esta "orientada a objetos "en lugar de" Java", así que me gustaría señalar que la respuesta de ChssPly76 depende del lenguaje. En Python, por ejemplo, no hay razón para usar getters y setters. Si necesita cambiar el comportamiento, puede usar una propiedad, que envuelve un getter y setter alrededor del acceso a 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
Author: jcdyer,
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-10-14 18:54:52

Bueno, solo quiero agregar que incluso si a veces son necesarios para la encapsulación y seguridad de sus variables / objetos, si queremos codificar un Programa orientado a Objetos reales, entonces necesitamos DEJE DE ABUSAR DE LOS ACCESORES, porque a veces dependemos mucho de ellos cuando no es realmente necesario y eso hace casi lo mismo que si pusiéramos las variables públicas.

 23
Author: Jorge Aguilar,
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-08-22 14:47:41

Sé que es un poco tarde, pero creo que hay algunas personas que están interesadas en el rendimiento.

He hecho una pequeña prueba de rendimiento. Escribí una clase "NumberHolder" que, bueno, contiene un Entero. Puede leer ese entero usando el método getter anInstance.getNumber() o accediendo directamente al número usando anInstance.number. Mi programa lee el número 1,000,000,000 veces, a través de ambos sentidos. Ese proceso se repite cinco veces y se imprime la hora. Tengo lo siguiente resultado:

Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms

(El tiempo 1 es el camino directo, el Tiempo 2 es el que consigue)

Verás, el getter es (casi) siempre un poco más rápido. Luego lo intenté con diferentes números de ciclos. En lugar de 1 millón, usé 10 millones y 0.1 millones. Los resultados:

10 millones de ciclos:

Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms

Con 10 millones de ciclos, los tiempos son casi los mismos. Aquí hay 100 mil (0.1 millones) ciclos:

Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms

También con diferentes cantidades de ciclos, el getter es un poco más rápido que la forma normal. Espero que esto te haya ayudado.

 22
Author: kangalioo,
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
2018-05-09 09:09:55

Gracias, eso realmente aclaró mi pensamiento. Ahora aquí hay (casi) 10 (casi) buenas razones para NO usar getters y setters:

  1. Cuando te das cuenta de que necesitas hacer algo más que simplemente establecer y obtener el valor, puedes hacer que el campo sea privado, lo que instantáneamente te dirá dónde has accedido directamente a él.
  2. Cualquier validación que realice allí solo puede ser libre de contexto, lo que rara vez ocurre en la práctica.
  3. Puede cambiar el valor que se establece - este es un pesadilla absoluta cuando la persona que llama te pasa un valor que ellos [shock horror] quieren que guardes COMO ESTÁ.
  4. Puede ocultar la representación interna - fantástico, por lo que se está asegurando de que todas estas operaciones son simétricas derecho?
  5. Ha aislado su interfaz pública de los cambios bajo las hojas - si estaba diseñando una interfaz y no estaba seguro de si el acceso directo a algo estaba bien, entonces debería haber seguido diseñando.
  6. Algunas bibliotecas espere esto , pero no muchos: reflexión, serialización, objetos simulados, todos funcionan bien con campos públicos.
  7. Heredando esta clase, puede anular la funcionalidad predeterminada, en otras palabras, realmente puede confundir a los llamantes no solo ocultando la implementación sino haciéndola inconsistente.

Los últimos tres me voy (N/A o D/C)...

 21
Author: StackedCrooked,
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-08-23 21:25:59

No use getters setters a menos que sea necesario para su entrega actual, es decir, no piense demasiado en lo que sucedería en el futuro, si algo se cambia es una solicitud de cambio en la mayoría de las aplicaciones de producción, sistemas.

Piense simple, fácil, agregue complejidad cuando sea necesario.

No me aprovecharía de la ignorancia de los propietarios de negocios de profundo conocimiento técnico solo porque creo que es correcto o me gusta el enfoque.

Tengo sistema masivo escrito sin getters setters solo con modificadores de acceso y algunos métodos para validar la lógica de n perform biz. Si es absolutamente necesario. Usa cualquier cosa.

 15
Author: Mohamed,
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-07-14 16:20:27

Pasé bastante tiempo pensando en esto para el caso Java, y creo que las razones reales son:

  1. Código a la interfaz, no a la implementación
  2. Las interfaces solo especifican métodos, no campos

En otras palabras, la única manera de especificar un campo en una interfaz es proporcionando un método para escribir un nuevo valor y un método para leer el valor actual.

Esos métodos son los infames getter y setter....

 14
Author: Thorbjørn Ravn Andersen,
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-11-07 21:55:17

Usamos getters y setters:

  • para la reutilización
  • para realizar la validación en etapas posteriores de la programación

Los métodos Getter y setter son interfaces públicas para acceder a miembros de clases privadas.


Mantra de encapsulación

El mantra de la encapsulación es hacer que los campos sean privados y los métodos públicos.

Métodos Getter: Podemos tener acceso a variables privadas.

Setter Métodos: podemos modificar los campos privados.

Aunque los métodos getter y setter no agregan nueva funcionalidad, podemos cambiar de opinión volver más tarde para hacer que ese método

  • mejor;
  • más seguro; y
  • más rápido.

En cualquier lugar donde se puede usar un valor, se puede agregar un método que devuelve ese valor. En lugar de:

int x = 1000 - 500

Use

int x = 1000 - class_name.getValue();

En el lego términos

Representación de la clase" Persona"

Supongamos que necesitamos almacenar los detalles de esto Person. Este Person tiene los campos name, age y sex. Hacer esto implica crear métodos para name, age y sex. Ahora si necesitamos crear otra persona, se hace necesario crear los métodos para name, age, sex todo de nuevo.

En lugar de hacer esto, podemos crear un bean class(Person) con los métodos getter y setter. Así que mañana podemos crear objetos de este Frijol class(Person class) cada vez que necesidad de añadir una nueva persona (ver la figura). Por lo tanto, estamos reutilizando los campos y métodos de la clase bean, que es mucho mejor.

 14
Author: Devrath,
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
2013-12-19 05:22:04

Puede ser útil para la carga lenta. Digamos que el objeto en cuestión está almacenado en una base de datos, y no quieres ir a buscarlo a menos que lo necesites. Si el objeto es recuperado por un getter, entonces el objeto interno puede ser null hasta que alguien lo solicite, entonces puedes ir a buscarlo en la primera llamada al getter.

Tenía una clase de página base en un proyecto que me fue entregada que estaba cargando algunos datos de un par de llamadas a servicios web diferentes, pero los datos en esas llamadas a servicios web no siempre se usa en todas las páginas secundarias. Los servicios web, para todos los beneficios, son pioneros en nuevas definiciones de" lento", por lo que no desea hacer una llamada a un servicio web si no tiene que hacerlo.

Me moví de los campos públicos a los getters, y ahora los getters revisan la caché, y si no está allí, llaman al servicio web. Así que con un poco de envoltura, se evitaron muchas llamadas de servicio web.

Así que el getter me salva de intentar averiguar, en cada página infantil, lo que necesitaré. Si lo necesito, llamo el getter, y va a encontrarlo para mí si no lo tengo ya.

    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }
 14
Author: quillbreaker,
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
2014-09-19 18:20:55

Un aspecto que me perdí en las respuestas hasta ahora, la especificación de acceso:

  • para los miembros, solo tiene una especificación de acceso para configurar y obtener
  • para setters y getters puedes afinarlo y definirlo por separado
 12
Author: jdehaan,
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-10-14 18:38:28

En lenguajes que no soportan "propiedades" (C++, Java) o requieren recompilación de clientes al cambiar campos a propiedades (C#), usar métodos get/set es más fácil de modificar. Por ejemplo, agregar lógica de validación a un método setFoo no requerirá cambiar la interfaz pública de una clase.

En lenguajes que soportan propiedades "reales" (Python, Ruby, tal vez Smalltalk?) no tiene sentido obtener/establecer métodos.

 10
Author: John Millikin,
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-10-14 19:13:42

EDIT: Respondí esta pregunta porque hay un montón de gente aprendiendo programación preguntando esto, y la mayoría de las respuestas son muy competentes técnicamente, pero no son tan fáciles de entender si eres un novato. Todos éramos novatos, así que pensé en probar suerte con una respuesta más amigable para novatos.

Los dos principales son el polimorfismo y la validación. Incluso si es sólo una estructura de datos estúpida.

Digamos que tenemos esta clase simple:

public class Bottle {
  public int amountOfWaterMl;
  public int capacityMl;
}

Una clase muy simple que contiene cuánto líquido hay en él, y cuál es su capacidad (en mililitros).

Lo que sucede cuando lo hago:

Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacity = 1000;

Bueno, no esperarías que eso funcionara, ¿verdad? Quieres que haya algún tipo de control de cordura. Y lo que es peor, ¿qué pasa si nunca he especificado la capacidad máxima? Cielos, tenemos un problema.

Pero también hay otro problema. ¿Qué pasaría si las botellas fueran solo un tipo de contenedor? ¿Y si tuviéramos varios contenedores, todos con capacidades y cantidades de líquido lleno? Si podríamos hacer una interfaz, podríamos dejar que el resto de nuestro programa acepte esa interfaz, y botellas, bidones y todo tipo de cosas funcionarían intercambiablemente. ¿No sería mejor? Dado que las interfaces exigen métodos, esto también es algo bueno.

Terminaríamos con algo como:

public interface LiquidContainer {
  public int getAmountMl();
  public void setAmountMl(int amountMl);
  public int getCapacityMl();
  public void setCapcityMl(int capacityMl);
}

Genial! Y ahora simplemente cambiamos la botella a esto:

public class Bottle extends LiquidContainer {
  private int capacityMl;
  private int amountFilledMl;
  public Bottle(int capacityMl, int amountFilledMl) {
    this.capacityMl = capacityMl;
    this.amountFilledMl = amountFilledMl;
    checkNotOverFlow();
  }

  public int getAmountMl() {
    return amountFilledMl;
  }

  public void setAmountMl(int amountMl) {
     this.amountFilled = amountMl;
     checkNotOverFlow();
  }
  public int getCapacityMl() {
    return capacityMl;
  public void setCapcityMl(int capacityMl) {
    this.capacityMl = capacityMl;
    checkNotOverFlow();
  }

  private void checkNotOverFlow() {
    if(amountOfWaterMl > capacityMl) {
      throw new BottleOverflowException();
    }
}

Dejaré la definición de la excepción Bottleoverflow como un ejercicio para el lector.

Ahora observe cuánto esto es más robusto. Podemos tratar con cualquier tipo de contenedor en nuestro código ahora aceptando LiquidContainer en lugar de Bottle. Y cómo estas botellas tratan con este tipo de cosas puede diferir. Puede tener botellas que escriben su estado en el disco cuando cambia, o botellas que guardan en bases de datos SQL o GNU sabe qué más.

Y todos estos pueden tener diferentes maneras de manejar varios whoopsies. La botella solo comprueba y si se está desbordando lanza una excepción RuntimeException. Pero eso podría ser no es lo correcto. (Hay una discusión útil sobre el manejo de errores, pero lo mantengo muy simple aquí a propósito. Las personas en los comentarios probablemente señalarán los defectos de este enfoque simplista. ;) )

Y sí, parece que pasamos de una idea muy simple a obtener respuestas mucho mejores rápidamente.

También está la tercera cosa que no todos han abordado: los getters y setters usan llamadas a métodos. Eso significa que se ven como métodos normales en todas partes hacer. En lugar de tener una sintaxis específica extraña para los DTO y esas cosas, tienes lo mismo en todas partes.

 9
Author: Haakon Løtveit,
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
2015-11-29 14:37:50

Uno de los principios básicos del diseño OO: Encapsulación!

Le da muchos beneficios, uno de los cuales es que puede cambiar la implementación del getter/setter detrás de escena, pero cualquier consumidor de ese valor continuará trabajando mientras el tipo de datos siga siendo el mismo.

 6
Author: Justin Niessner,
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-10-14 18:25:19

Desde el punto de vista del diseño orientado a objetos, ambas alternativas pueden ser perjudiciales para el mantenimiento del código al debilitar la encapsulación de las clases. Para una discusión usted puede mirar en este excelente artículo: http://typicalprogrammer.com/?p=23

 4
Author: andrers52,
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-04-30 19:08:29

Debes usar getters y setters cuando:

  • Estás tratando con algo que es conceptualmente un atributo, pero:
    • Su lenguaje no tiene propiedades (o algún mecanismo similar, como trazas de variables de Tcl), o
    • El soporte de propiedades de su idioma no es suficiente para este caso de uso, o
    • Las convenciones idiomáticas de su lenguaje (o a veces las de su framework) alientan a los getters o setters para este caso de uso.

Así que esto es muy raramente una pregunta general OO; es una pregunta específica del idioma, con diferentes respuestas para diferentes idiomas (y diferentes casos de uso).


Desde el punto de vista de la teoría OO, los getters y setters son inútiles. La interfaz de tu clase es lo que hace, no cuál es su estado. (Si no, has escrito la clase equivocada.) En casos muy simples, donde lo que hace una clase es simplemente, por ejemplo, representar un punto en coordenadas rectangulares, * los atributos son parte de la interfaz; getters y los setters lo nublan. Pero en cualquier caso que no sea muy simple, ni los atributos ni los getters y setters forman parte de la interfaz.

Dicho de otra manera: Si crees que los consumidores de tu clase ni siquiera deberían saber que tienes un atributo spam, mucho menos ser capaz de cambiarlo de cualquier manera, entonces darles un método set_spam es lo último que quieres hacer.

* Incluso para esa clase simple, es posible que no necesariamente desee permitir establecer los valores x y y. Si esto es realmente una clase, ¿no debería tener métodos como translate, rotate, etc.? Si es solo una clase porque su lenguaje no tiene registros / estructuras / tuplas con nombre, entonces esto no es realmente una cuestión de OO {


Pero nadie está haciendo diseño general de OO. Están haciendo diseño e implementación en un lenguaje específico. Y en algunos idiomas, los getters y setters están lejos de ser inútiles.

Si su lenguaje no tiene propiedades, entonces la única manera de representar algo eso es conceptualmente un atributo, pero en realidad se calcula, o valida, etc., es a través de getters y setters.

Incluso si su lenguaje tiene propiedades, puede haber casos en los que son insuficientes o inapropiados. Por ejemplo, si desea permitir que las subclases controlen la semántica de un atributo, en lenguajes sin acceso dinámico, una subclase no puede sustituir una propiedad calculada por un atributo.

En cuanto al "¿qué pasa si quiero cambiar mi implementación más tarde?" pregunta (que se repite varias veces en diferentes términos tanto en la pregunta del OP como en la respuesta aceptada): Si realmente es un cambio de implementación puro, y comenzó con un atributo, puede cambiarlo a una propiedad sin afectar la interfaz. A menos, por supuesto, que tu lenguaje no lo soporte. Así que este es realmente el mismo caso de nuevo.

Además, es importante seguir los modismos del idioma (o marco) que está utilizando. Si escribes un hermoso código estilo Ruby en C#, cualquier desarrollador experimentado de C # que no sea usted tendrá problemas para leerlo, y eso es malo. Algunas lenguas tienen culturas más fuertes alrededor de sus convenciones que otras.- y puede que no sea una coincidencia que Java y Python, que están en extremos opuestos del espectro de cómo son los getters idiomáticos, tengan dos de las culturas más fuertes.

Más allá de los lectores humanos, habrá bibliotecas y herramientas que esperan que sigas las convenciones, y hagas tu vida más difícil si Enganchar widgets de Interface Builder a cualquier cosa que no sean propiedades de ObjC, o usar ciertas bibliotecas de burla de Java sin getters, solo está haciendo su vida más difícil. Si las herramientas son importantes para ti, no luches contra ellas.

 4
Author: abarnert,
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
2014-08-19 04:47:03

Los métodos Getter y setter son métodos de acceso, lo que significa que generalmente son una interfaz pública para cambiar miembros de clases privadas. Se utilizan los métodos getter y setter para definir una propiedad. Accede a los métodos getter y setter como propiedades fuera de la clase, aunque los defina dentro de la clase como métodos. Las propiedades fuera de la clase pueden tener un nombre diferente del nombre de la propiedad de la clase.

Hay algunas ventajas al usar los métodos getter y setter, tales como la capacidad de permitirle crear miembros con una funcionalidad sofisticada a la que puede acceder como propiedades. También le permiten crear propiedades de solo lectura y solo escritura.

Aunque los métodos getter y setter son útiles, debe tener cuidado de no abusar de ellos porque, entre otros problemas, pueden hacer que el mantenimiento del código sea más difícil en ciertas situaciones. Además, proporcionan acceso a la implementación de su clase, como miembros públicos. Práctica OOP desalienta el acceso directo a propiedades dentro de una clase.

Cuando escriba clases, siempre se le recomienda que haga privadas la mayor cantidad posible de variables de instancia y agregue los métodos getter y setter en consecuencia. Esto se debe a que hay varias veces en las que es posible que no desee permitir que los usuarios cambien ciertas variables dentro de sus clases. Por ejemplo, si tiene un método estático privado que rastrea el número de instancias creadas para una clase específica, no desea que un usuario modifique ese contador mediante código. Solo la sentencia constructor debe incrementar esa variable cada vez que se llama. En esta situación, puede crear una variable de instancia privada y permitir un método getter solo para la variable contador, lo que significa que los usuarios pueden recuperar el valor actual solo mediante el método getter, y no podrán establecer nuevos valores utilizando el método setter. Crear un getter sin un setter es una forma sencilla de hacer que ciertas variables de tu clase sean de solo lectura.

 3
Author: Sumit Singh,
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-08-30 13:02:26

El código evoluciona. privatees ideal para cuando necesita protección de miembros de datos. Eventualmente todas las clases deberían ser una especie de" miniprogramas " que tienen una interfaz bien definida que no puedes simplemente atornillar con las partes internas de.

Dicho esto, El desarrollo de software no se trata de establecer esa versión final de la clase como si estuviera presionando alguna estatua de hierro fundido en el primer intento. Mientras trabajas con él, el código es más como arcilla. It evoluciona a medida que lo desarrolla y aprende más sobre el dominio del problema que está resolviendo. Durante el desarrollo, las clases pueden interactuar entre sí de lo que deberían (dependencia que planea eliminar), fusionarse o dividirse. Así que creo que el debate se reduce a la gente que no quiere escribir religiosamente

int getVar() const { return var ; }

Así que tienes:

doSomething( obj->getVar() ) ;

En lugar de

doSomething( obj->var ) ;

No solo es getVar() visualmente ruidoso, sino que da la ilusión de que gettingVar() es de alguna manera un proceso más complejo de lo que realmente es. Cómo usted (como el escritor de la clase) considera la santidad de var es particularmente confuso para un usuario de su clase si tiene un creador de passthru then entonces parece que está colocando estas puertas para "proteger" algo que insiste en que es valioso, (la santidad de var) pero aún así incluso usted reconoce que la protección de var no vale mucho por la capacidad de set var a cualquier valor que quieran, sin que siquiera espíes lo que están haciendo.

Así que programa de la siguiente manera (asumiendo un enfoque de tipo "ágil" ie es decir, cuando escribo código sin saber exactamente lo que va a hacer/no tengo tiempo o experiencia para planificar un elaborado conjunto de interfaces de estilo cascada):

1) Comience con todos los miembros públicos para objetos básicos con datos y comportamiento. Esta es la razón por la que en todo mi código de "ejemplo" de C++ me verás usando struct en lugar de class en todas partes.

2) Cuando el comportamiento interno de un objeto para un miembro de datos se vuelve lo suficientemente complejo, (por ejemplo, le gusta mantener un std::list interno en algún tipo de orden), las funciones de tipo accesor se escriben. Debido a que estoy programando por mí mismo, no siempre establezco el miembro private de inmediato, pero en algún momento de la evolución de la clase, el miembro será "promovido" a protected o private.

3) Clases que están completamente desarrolladas y tienen reglas estrictas sobre sus componentes internos (es decir, ellos saben exactamente lo que están haciendo, y no debes "joder" (término técnico) con sus componentes internos) reciben la designación class, miembros privados predeterminados, y solo unos pocos miembros selectos pueden ser public.

Encuentro que este enfoque me permite evitar sentarme allí y escribir religiosamente getter / setters cuando muchos miembros de datos migran, cambian de lugar, etc. durante las primeras etapas de la evolución de una clase.

 3
Author: bobobobo,
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
2013-05-05 02:13:09

Hay una buena razón para considerar el uso de accesores es que no hay herencia de propiedad. Véase el siguiente ejemplo:

public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}

Salida:

0
0
4
 3
Author: GeZo,
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
2014-05-13 09:47:35

Otro uso (en lenguajes que soportan propiedades) es que los setters y getters pueden implicar que una operación no es trivial. Por lo general, desea evitar hacer cualquier cosa que es computacionalmente caro en una propiedad.

 2
Author: Jason Baker,
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-10-14 18:27:45

Los Getters y setters se utilizan para implementar dos de los aspectos fundamentales de la Programación Orientada a Objetos que son:

  1. Abstracción
  2. Encapsulación

Supongamos que tenemos una clase de Empleado:

package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }

Aquí los detalles de implementación del Nombre Completo están ocultos para el usuario y no son accesibles directamente para el usuario, a diferencia de un atributo público.

 2
Author: Pritam Banerjee,
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
2016-07-05 22:32:35

Una ventaja relativamente moderna de los getters/setters es que facilita la búsqueda de código en editores de código etiquetados (indexados). Por ejemplo, si desea ver quién establece un miembro, puede abrir la jerarquía de llamadas del configurador.

Por otro lado, si el miembro es público, las herramientas no permiten filtrar el acceso de lectura/escritura del miembro. Así que tienes que caminar a pesar de todos los usos del miembro.

 2
Author: Rakesh Singh,
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
2017-01-03 16:10:02

En un lenguaje orientado a objetos los métodos, y sus modificadores de acceso, declaran la interfaz para ese objeto. Entre el constructor y los métodos accessor y mutator es posible que el desarrollador controle el acceso al estado interno de un objeto. Si las variables simplemente se declaran públicas, entonces no hay forma de regular ese acceso. Y cuando estamos usando setters podemos restringir el usuario para la entrada que necesitamos. Significa que la alimentación para esa misma variable vendrá a través de una adecuada canal y el canal está predefinido por nosotros. Así que es más seguro usar setters.

 2
Author: Antz,
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
2017-11-04 17:11:33

Además, esto es para "preparar el futuro" de su clase. En particular, cambiar de un campo a una propiedad es una ruptura ABI, por lo que si luego decide que necesita más lógica que solo "establecer/obtener el campo", entonces necesita romper ABI, lo que por supuesto crea problemas para cualquier otra cosa ya compilada contra su clase.

 1
Author: Pete,
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-10-14 18:25:59

Me gustaría lanzar la idea de anotación : @getter y @setter. Con @getter, deberías ser capaz de obj = class.campo, pero no clase.field = obj. Con @setter, viceversa. Con @getter y @setter deberías poder hacer ambas cosas. Esto preservaría la encapsulación y reduciría el tiempo al no llamar a métodos triviales en tiempo de ejecución.

 1
Author: fastcodejava,
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-10-14 22:40:24