Miembros de Datos públicos vs Getters, Setters


Actualmente estoy trabajando en Qt y so C++. Estoy teniendo clases que tienen miembros de datos privados y funciones de miembros públicos. Tengo getters y setters públicos para los miembros de datos disponibles en la clase.

Ahora mi pregunta es, si tenemos getters y setters para miembros de datos en nuestras clases, ¿cuál es el punto en hacer que esos miembros de datos sean privados? Estoy de acuerdo en tener miembros de datos privados en clases Base suena lógico. Pero además de eso, tener miembros privados y también lo hacen sus captores y armadores no parecen ser lógicos para mí.

O en su lugar ¿podemos hacer que todas las variables sean públicas para que no haya necesidad de getters y setters? ¿Es una buena práctica tenerlos? Sé que tener miembros privados asegura la abstracción de datos, pero tener getters y setters realmente permite el acceso a esas variables con bastante facilidad. Cualquier sugerencia al respecto es bienvenida.

Author: liaK, 2010-06-04

15 answers

Ninguno. Deberías tener métodos que hagan las cosas. Si una de esas cosas sucede para corresponder con una variable interna específica que es grande pero no debe haber nada que telegrafíe esto a los usuarios de su clase.

Los datos privados son privados, por lo que puede reemplazar la implementación cuando lo desee (y puede hacer reconstrucciones completas, pero eso es un problema diferente). Una vez que dejes que el Genio salga de la botella, te resultará imposible empujarlo de nuevo.

EDITAR: Después de un comentario Hice otra respuesta.

Mi punto aquí es que usted está haciendo la pregunta equivocada. No existe una buena práctica con respecto al uso de getters/setters o tener miembros públicos. Solo hay lo que es mejor para su objeto específico y cómo modela alguna cosa específica del mundo real (o cosa imaginaria tal vez en el caso del juego).

Personalmente los getters/setters son el menor de dos males. Porque una vez que empiezas a hacer getters / setters, la gente deja de diseñar objetos con un ojo crítico hacia qué datos deben ser visibles y qué datos no. Con los miembros públicos es aún peor porque la tendencia se vuelve a hacer todo público.

En su lugar, examine lo que hace el objeto y lo que significa que algo sea ese objeto. Luego cree métodos que proporcionen una interfaz natural en ese objeto. Es que la interfaz natural implica exponer algunas propiedades internas utilizando getters y setters que así sea. Pero la parte importante es que lo pensaste antes de tiempo y creó los getters / setters por una razón justificada de diseño.

 68
Author: jmucchiello,
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
2010-06-04 20:16:15

No, no es ni remotamente lo mismo.

Hay diferentes niveles de protección / ocultación de implementación que se pueden lograr mediante diferentes enfoques para una interfaz de clase:


1. Miembro de datos públicos:

  • proporciona acceso de lectura y escritura (si no const) al miembro de datos
  • expone el hecho de que el objeto de datos existe físicamente y es físicamente un miembro de esta clase (permite crear punteros de tipo puntero a miembro a esos datos miembro)
  • proporciona acceso lvalue al miembro de datos (permite crear punteros ordinarios al miembro)


2. Un método que devuelve una referencia a una pieza de datos (posiblemente a un miembro de datos privado):

  • proporciona acceso de lectura y escritura (si no const) a los datos
  • expone el hecho de que el objeto de datos existe físicamente, pero no expone que es físicamente un miembro de esta clase (no permite crear punteros de tipo puntero a miembro a los datos)
  • proporciona acceso lvalue a los datos (permite crear punteros ordinarios a ellos)


3. Métodos Getter y / o setter (posiblemente accediendo a un miembro de datos privados):

  • proporciona acceso de lectura y/o escritura a la propiedad
  • no expone el hecho de que el objeto de datos existe físicamente, y mucho menos físicamente presente en esta clase (no permite crear punteros de tipo puntero a miembro para que datos, o cualquier tipo de punteros para el caso)
  • no proporciona acceso lvalue a los datos (no permite crear punteros ordinarios a ellos)

El enfoque getter/setter ni siquiera expone el hecho de que la propiedad está implementada por un objeto físico. Es decir, puede que no haya ningún miembro de datos físicos detrás del par getter / setter.

Teniendo en cuenta lo anterior, es extraño ver a alguien afirmar que un par getter y setter es lo mismo que un miembro de datos públicos. De hecho, no tienen nada en común.

Por supuesto, hay variaciones de cada enfoque. Un método getter, por ejemplo, podría devolver una referencia const a los datos, lo que los colocaría en algún lugar entre (2) y (3).

 33
Author: AnT,
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 01:50:34

Si tiene getters y setters para cada uno de sus elementos de datos, no tiene sentido hacer que los datos sean privados. Es por eso que tener getters y setters para cada uno de sus elementos de datos es una mala idea. Considere la clase std::string: (probablemente) tiene UN getter, la función size (), y ningún setter en absoluto.

O considere un objeto BankAccount - ¿deberíamos tener SetBalance() setter para cambiar el balance actual? No, la mayoría de los bancos no le agradecerán por implementar tal cosa. En su lugar, queremos algo como ApplyTransaction( Transaction & tx ).

 23
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
2010-06-04 19:17:08

Hacer públicos los datos. En el caso (bastante improbable) de que algún día necesite lógica en el "getter" o "setter", puede cambiar el tipo de datos a una clase proxy que sobrecargue operator= y/o operator T (donde T=cualquier tipo que esté usando ahora) para implementar la lógica necesaria.

Editar: la idea de que controlar el acceso a los datos constituye encapsulación es básicamente falsa. La encapsulación consiste en ocultar los detalles de la implementación (¡en general!) no controlar el acceso a datos.

La encapsulación es complementaria a la abstracción: la abstracción se ocupa del comportamiento externamente visible del objeto, mientras que la encapsulación se ocupa de ocultar los detalles de cómo se implementa ese comportamiento.

Usando un getter o setter en realidad reduce el nivel de abstracción y expone la implementación requires requiere que el código cliente sea consciente de que esta clase en particular implementa lo que es lógicamente "data" como un par de funciones (el getter y el setter). Usando un proxy como he sugerido anteriormente proporciona real encapsulación except excepto por un caso de esquina oscura, completamente oculta el hecho de que lo que es lógicamente una pieza de datos es realmente implementado a través de un par de funciones.

Por supuesto, esto debe mantenerse en contexto: para algunas clases, "datos" no es una buena abstracción en absoluto. En términos generales, si puede proporcionar operaciones de mayor nivel en lugar de datos, es preferible. Sin embargo, hay clases para que la abstracción más utilizable es leer y escribir datos -- y cuando ese es el caso, los datos (abstraídos) deben hacerse visibles al igual que cualquier otro dato. El hecho de que obtener o establecer el valor puede implicar más que una simple copia de bits es un detalle de implementación que debe ocultarse al usuario.

 11
Author: Jerry Coffin,
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
2010-06-04 19:33:25

Los Getters y Setters le permiten aplicar lógica a la entrada/salida de los miembros privados, por lo tanto, controlar el acceso a los datos (Encapsulación a aquellos que conocen sus términos OO).

Las variables públicas dejan los datos de su clase abiertos al público para una manipulación incontrolada y no validada que casi siempre es indeseable.

Tienes que pensar en estas cosas a largo plazo también. Es posible que no tenga validación ahora (por lo que las variables públicas parecen ser una buena idea), pero hay una posibilidad de que sean añadidos en el camino. Agregarlos antes de tiempo deja el marco por lo que hay menos re-factorizar el raod sin mencionar que la validación no romperá el código dependiente de esta manera).

Tenga en cuenta, sin embargo, que eso no significa que Todas y cada una de las variables privadas necesite su propio getter/setter. Neil trae un buen punto en su ejemplo bancario que a veces los Getters / Setters simplemente no tienen sentido.

 9
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
2010-06-04 19:20:27

Si está bastante seguro de que su lógica es simple, y nunca necesita hacer otra cosa al leer/escribir una variable, es mejor mantener los datos públicos. En el caso de C++, prefiero usar struct en lugar de class para enfatizar el hecho de que los datos son públicos.

Sin embargo, muy a menudo necesita hacer algunas otras cosas al acceder a los miembros de datos, o desea darse libertad para agregar esta lógica más adelante. En este caso, getters y setters son una buena idea. Tu cambio será transparente a los clientes de su código.

Un ejemplo simple de funcionalidad adicional - es posible que desee registrar una cadena de depuración cada vez que acceda a una variable.

 5
Author: Igor Krivokon,
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
2010-06-04 19:16:44

Aparte de las preocupaciones de encapsulación (que son razón suficiente), es muy fácil establecer un punto de interrupción cada vez que se establece/accede a la variable cuando tiene getters/setters.

 5
Author: BlueRaja - Danny Pflughoeft,
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
2010-06-04 19:18:14

Las razones para usar campos públicos en lugar de getters y setters incluyen:

  1. No hay valores ilegales.
  2. Se espera que el cliente lo edite.
  3. Para poder escribir cosas como object.X. Y = Z.
  4. Para hacer una fuerte promesa de que el valor es solo un valor y no hay efectos secundarios asociados con él (y no lo será en el futuro tampoco).

Dependiendo del tipo de software en el que trabaje, estos podrían ser casos realmente excepcionales (y si crees que te has encontrado con uno, probablemente estés equivocado) o podrían ocurrir todo el tiempo. Realmente depende.

(De Diez Preguntas sobre Programación Basada en Valores.)

 4
Author: Ian Goldby,
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-06-25 14:07:14

Sobre una base estrictamente práctica, le sugiero que comience por hacer que todos sus miembros de datos sean privados, Y hagan que sus getters y setters sean privados. A medida que descubra lo que el resto del mundo (es decir, su "(l)comunidad de usuarios") realmente necesita, puede exponer los getters y/o setters apropiados, o escribir accesores públicos controlados apropiadamente.

También (para el beneficio de Neil), durante el tiempo de depuración, a veces es útil tener un lugar conveniente para colgar impresiones de depuración, y otras acciones, cuando un miembro de datos en particular es leído o escrito. Con getters y setters, esto es fácil. Con los miembros de datos públicos, es un gran dolor en el posterior.

 3
Author: John R. Strohm,
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
2010-06-04 19:16:06

Siempre he pensado que los getters y setters son deliberadamente verbosos en la mayoría de los lenguajes de programación específicamente para hacerte pensar dos veces antes de usarlos: ¿por qué tu persona que llama necesita saber sobre el funcionamiento interno de tu clase debería ser la pregunta en el frente de tu mente?

 2
Author: blissapp,
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
2010-06-04 19:27:33

Creo que usar getters y setters simplemente para obtener y establecer el valor es inútil. No hay diferencia entre un miembro público y uno privado con tales métodos. Use getters y setters solo cuando necesite controlar los valores de alguna manera o cuando piense que podría ser útil en el futuro (agregar alguna lógica no le hará editar el resto del código).

Como referencia, lea las directrices de C++ (C. 131)

 2
Author: Hitokage,
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-10-10 16:52:28

Sugiero que no tengas miembros de datos públicos (excepto para estructuras POD). Tampoco recomiendo que tenga getters y setters para todos sus miembros de datos. En su lugar, defina una interfaz pública limpia para su clase. Esto puede incluir métodos que obtienen y / o establecen valores de propiedad, y esas propiedades pueden implementarse como variables miembro. Pero no hagas getters y setters para todos tus miembros.

La idea es separar la interfaz de la implementación, lo que le permite modificar la implementación sin que los usuarios de la clase tengan que cambiar su código. Si expone todo a través de getters y setters, no ha mejorado nada sobre el uso de datos públicos.

 1
Author: Fred Larson,
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
2010-06-04 19:14:36

El uso de getters y setters le permitirá modificar la forma en que le da los valores al usuario.

Considere lo siguiente:

double premium;
double tax;

Luego escribes código por todo el lugar usando este premium valor para obtener la prima:

double myPremium = class.premium;

Sus especificaciones acaban de cambiar y la prima desde el punto de vista del usuario debe ser premium + tax

Tendrá que modificar en todas partes que ese valor premium se esté utilizando en su código, y agregarle tax.

Si en cambio usted implemented it as such:

double premium;
double tax;

double GetPremium(){return premium;};

Todo tu código estaría usando GetPremium() y tu tax cambio sería una línea:

double premium;
double tax;

double GetPremium(){return premium + tax;};
 1
Author: Ben Burnett,
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
2010-06-04 19:33:33

El valor devuelto también afecta el uso de getters y setters. Es una diferencia para obtener el valor de una variable o para obtener acceso a la variable miembro de datos privados. By-value mantiene la integridad, by-reference o by-pointer no tanto.

 0
Author: DaClown,
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
2010-06-04 19:15:59

Los Getters y Setters existen principalmente para que podamos controlar cómo se obtienen los miembros y cómo se establecen. Los getters y setters no existen solo como una forma de acceder a un miembro específico, sino para asegurarnos de que antes de intentar establecer un miembro, que tal vez cumpla ciertas condiciones, o si lo recuperamos, podríamos controlar que devolvamos una copia de ese miembro en el caso de un tipo no primitivo. En general, debe intentar usar g / s'ers cuando desee canalizar cómo debe interactuar un miembro de datos con, sin ellos causaría que el miembro se utilice de manera adhoc.

 0
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
2014-10-27 19:28:31