Getters y setters a menudo son criticados por no ser OO adecuados. Por otro lado, la mayoría del código OO que he visto tiene extensores captadores y establecedores.
¿Cuándo se justifican getters y setters? ¿Intentas evitar usarlos? ¿Se usan en exceso en general?
Si su idioma favorito tiene propiedades (el mío), entonces esas cosas también se consideran captadores y establecedores para esta pregunta. Son lo mismo desde una perspectiva de metodología OO. Simplemente tienen una sintaxis más agradable.
Fuentes de crítica de Getter / Setter (algunas tomadas de comentarios para darles una mejor visibilidad):
- http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
- http://typicalprogrammer.com/?p=23
- http://c2.com/cgi/wiki?AccessorsAreEvil
- http://www.darronschall.com/weblog/2005/03/no-brain-getter-and-setters.cfm
- http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and
- http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html
Para expresar la crítica simplemente: Getters y Setters le permiten manipular el estado interno de los objetos desde el exterior del objeto. Esto viola la encapsulación. Solo el objeto mismo debe preocuparse por su estado interno.
Y un ejemplo Versión procesal de código.
struct Fridge
{
int cheese;
}
void go_shopping(Fridge fridge)
{
fridge.cheese += 5;
}
Versión del código del mutador:
class Fridge
{
int cheese;
void set_cheese(int _cheese) { cheese = _cheese; }
int get_cheese() { return cheese; }
}
void go_shopping(Fridge fridge)
{
fridge.set_cheese(fridge.get_cheese() + 5);
}
Los captadores y definidores hicieron el código mucho más complicado sin permitir una encapsulación adecuada. Debido a que el estado interno es accesible para otros objetos, no ganamos mucho al agregar estos captadores y establecedores.
La pregunta se ha discutido previamente en Stack Overflow:
fuente
Getters and setters are often criticized as being not proper OO
- Cita, por favor.Respuestas:
Tener captadores y establecedores no interrumpe en sí mismo la encapsulación. Lo que rompe la encapsulación es agregar automáticamente un getter y un setter para cada miembro de datos (cada campo , en la jerga de Java), sin pensarlo. Si bien esto es mejor que hacer públicos todos los miembros de datos, está a solo un paso de distancia.
El objetivo de la encapsulación no es que no pueda saber o cambiar el estado del objeto desde fuera del objeto, sino que debe tener una política razonable para hacerlo.
Algunos miembros de datos pueden ser completamente internos al objeto, y no deberían tener getters ni setters.
Algunos miembros de datos deben ser de solo lectura, por lo que pueden necesitar getters pero no setters.
Es posible que algunos miembros de datos deban mantenerse consistentes entre sí. En tal caso, no proporcionaría un setter para cada uno, sino un método único para configurarlos al mismo tiempo, de modo que pueda verificar la consistencia de los valores.
Es posible que algunos miembros de datos solo necesiten cambiarse de cierta manera, como aumentar o disminuir en una cantidad fija. En este caso, proporcionaría un método
increment()
y / odecrement()
método, en lugar de un setter.Sin embargo, otros pueden necesitar lectura y escritura, y tendrían un captador y un definidor.
Considere un ejemplo de a
class Person
. Digamos que una persona tiene un nombre, un número de seguro social y una edad. Digamos que no permitimos que las personas cambien sus nombres o números de seguridad social. Sin embargo, la edad de la persona debe incrementarse en 1 cada año. En este caso, proporcionaría un constructor que inicializaría el nombre y el SSN a los valores dados, y que inicializaría la edad a 0. También proporcionaría un métodoincrementAge()
, que aumentaría la edad en 1. También proporcionaría captadores para los tres. No se requieren setters en este caso.En este diseño, permite que el estado del objeto se inspeccione desde fuera de la clase, y permite que se cambie desde fuera de la clase. Sin embargo, no permite que el estado se cambie arbitrariamente. Existe una política que establece efectivamente que el nombre y el SSN no se pueden cambiar en absoluto, y que la edad se puede aumentar en 1 año a la vez.
Ahora digamos que una persona también tiene un salario. Y las personas pueden cambiar de trabajo a voluntad, lo que significa que su salario también cambiará. ¡Para modelar esta situación no tenemos otra manera que proporcionar un
setSalary()
método! Permitir que el salario se cambie a voluntad es una política perfectamente razonable en este caso.Por cierto, en su ejemplo, le daría a la clase
Fridge
los métodosputCheese()
ytakeCheese()
, en lugar deget_cheese()
yset_cheese()
. Entonces todavía tendrías encapsulación.fuente
La razón básica para obtener y establecer en Java es muy simple:
Por lo tanto, si desea permitir que un campo pase a través de la interfaz, necesitará un método de lector y escritor. Estos se llaman tradicionalmente getX y setX para el campo x.
fuente
De http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and
Estilo JavaBean:
Estilo OO:
Bueno, claramente prefiero el último enfoque; no sangra los detalles de implementación, es más simple y conciso, y toda la información necesaria se incluye con la llamada al método, por lo que es más fácil hacerlo bien. También prefiero configurar miembros privados utilizando parámetros en el constructor, siempre que sea posible.
Su pregunta es, ¿cuándo se justifica un getter / setter? Quizás cuando se necesita un cambio de modo, o si necesita interrogar un objeto para obtener información.
Al pensar en ello, cuando comencé a codificar en C #, escribí mucho código en el estilo Javabeans ilustrado anteriormente. Pero a medida que adquirí experiencia en el lenguaje, comencé a configurar más miembros en el constructor y a utilizar métodos que se parecían más al estilo OO anterior.
fuente
Cuando el comportamiento "get" y "set" realmente coinciden con el comportamiento en su modelo, que prácticamente nunca es .
Cualquier otro uso es solo una trampa porque el comportamiento del dominio comercial no está claro.
Editar
Es posible que esa respuesta parezca frívola, así que déjame expandirme. Las respuestas anteriores son en su mayoría correctas, pero se centran en los paradigmas de programación del diseño OO y algunos de los que pierden el panorama general. En mi experiencia, esto lleva a las personas a pensar que evitar los gettings y setters es una regla académica para los lenguajes de programación OO (por ejemplo, la gente piensa que reemplazar getters con propiedades es grandioso)
De hecho, es una consecuencia del proceso de diseño. No tiene que entrar en interfaces y encapsulación y patrones, discutiendo si rompe o no estos paradigmas y qué es o no es buena programación OO. El único punto que en última instancia importa es que si no hay nada en su dominio que funcione de esta manera al ponerlos, no está modelando su dominio.
La realidad es que es muy poco probable que cualquier sistema en su espacio de dominio tenga captadores y establecedores. No puede acercarse al hombre o la mujer responsable de la nómina y simplemente decir "Establezca este salario en X" o "Consígueme este salario" . Tal comportamiento simplemente no existe
Si está poniendo esto en su código, no está diseñando su sistema para que coincida con el modelo de su dominio. Sí, eso rompe las interfaces y la encapsulación, pero ese no es el punto. El punto es que estás modelando algo que no existe.
Además, probablemente se esté perdiendo un paso o proceso importante, porque probablemente haya una razón por la que no puedo simplemente acercarme a pagar y decir que establezca este salario en X.
Cuando las personas usan getters y setters, tienden a llevar las reglas de este proceso al lugar equivocado. Esto se está alejando de su dominio aún más. Usando el ejemplo del mundo real, es como un salario asumiendo que la persona aleatoria que entró tiene el permiso para obtener estos valores, de lo contrario no los pediría. No solo no es así como es el dominio, sino que de hecho miente sobre cómo es el dominio.
fuente
set/get
salario?Como regla general, getters y setters son una mala idea. Si un campo no es lógicamente parte de la interfaz y lo hace privado, está bien. Si es lógicamente parte de la interfaz y la haces pública, está bien. Pero si lo hace privado y luego se da la vuelta y lo vuelve público de manera efectiva al proporcionar un captador y configurador, volverá a donde comenzó, excepto que su código ahora es más detallado y ofuscado.
Obviamente, hay excepciones. En Java, es posible que deba usar interfaces. La biblioteca estándar de Java tiene requisitos de compatibilidad con versiones anteriores tan extremas que superan las medidas normales de calidad del código. Incluso es posible que en realidad estés lidiando con el legendario pero raro caso en el que hay una buena posibilidad de que luego puedas reemplazar un campo almacenado con un cálculo sobre la marcha sin romper la interfaz. Pero estas son excepciones. Getters y setters son un antipatrón que necesita una justificación especial.
fuente
si el campo es accesible directamente o mediante el método no es realmente importante.
Los invariantes de clase (útiles) son importantes. Y para preservarlos, a veces necesitamos no poder cambiar algo desde afuera. P.ej. Si tenemos clase Cuadrado con ancho y alto separados, cambiar uno de ellos hace que se convierta en algo más que cuadrado. Por lo tanto, necesitamos un cambio de método en el lado Si fuera un rectángulo, podríamos tener setters / public field. Pero establecer más de lo que probaría si es mayor que cero sería mejor.
Y en lenguajes concretos (por ejemplo, Java) hay razones por las cuales necesitamos esos métodos (interfaces). Y otra razón para el método es la compatibilidad (fuente y binario). Entonces es más fácil agregarlos y luego pensar si el campo público sería suficiente.
por cierto. Me gusta usar clases simples de valor inmutable con campos finales públicos.
fuente
Es posible que desee cambiar sus componentes internos a lo que sea mientras mantiene las interfaces iguales. Si sus interfaces no varían, las que codifique no se romperán. Todavía puede cambiar sus componentes internos como lo desee.
fuente
Mi enfoque es este:
Cuando espero jugar con los datos más adelante, se justifica un getter / setter. Además, si se produce un cambio, a menudo inserto los datos en un captador / configurador.
Si es una estructura POD, dejo las ranuras disponibles.
En un nivel más abstracto, la pregunta es "quién administra los datos", y eso depende del proyecto.
fuente
Si usar getters y setters se siente complicado, el problema podría ser el lenguaje, no el concepto en sí.
Aquí está el código del segundo ejemplo escrito en Ruby:
¿Te das cuenta de que se parece mucho al primer ejemplo en Java? Cuando los captadores y los setters son tratados como ciudadanos de primera clase, no son una tarea difícil de usar, y la flexibilidad adicional a veces puede ser una verdadera bendición; por ejemplo, podríamos decidir devolver un valor predeterminado para el queso en un refrigerador nuevo:
Por supuesto, habrá muchas variables que no deberían exponerse públicamente. Exponer innecesariamente las variables internas empeorará su código, pero difícilmente puede culpar a los captadores y establecedores.
fuente
Considere una
Size
clase que encapsula ancho y alto. Puedo eliminar los colocadores usando el constructor, pero ¿cómo me ayuda eso a dibujar un rectánguloSize
? Ancho y alto no son datos internos de la clase; son datos compartidos que deben estar disponibles para los consumidores de Size.Los objetos consisten en comportamientos y estados, o atributos. Si no hay un estado expuesto, solo los comportamientos son públicos.
Sin estado, ¿cómo ordenarías una colección de objetos? ¿Cómo buscarías una instancia específica de un objeto? Si solo usa constructores, ¿qué sucede cuando su objeto tiene una larga lista de atributos?
Ningún parámetro de método debe consumirse sin validación. Por lo tanto, es pereza escribir:
Si lo escribe de esa manera, entonces al menos se ha preparado para usar el configurador para la validación; es mejor que un campo público, pero apenas. Pero al menos tiene una interfaz pública consistente que puede volver y poner en reglas de validación sin romper el código de sus clientes.
Getters, setters, propiedades, mutadores, llámalos como quieras, pero son necesarios.
fuente
int
variable de instancia, por ejemplo, e imagine que decide agregar una regla de validación para aceptar solo valores no negativos. El problema es que el código de su cliente ya puede contar con la posibilidad de establecer en un valor negativo ...Si getters y setters violan la encapsulación y el verdadero OO, entonces estoy en serios problemas.
Siempre sentí que un objeto representa lo que se te viene a la mente que necesitas que haga.
Acabo de terminar de escribir un programa que genera laberintos en Java, y tengo una clase que representa "Cuadrados de laberintos". Tengo datos en esta clase que representan coordenadas, muros y booleanos, etc.
¡Tengo que tener alguna forma de cambiar / manipular / acceder a estos datos! ¿Qué hago sin captadores y colocadores? Java no usa propiedades y configurar todos mis datos que son locales para esta clase en público es DEFINITIVAMENTE una violación de encapsulación y OO.
fuente
En primer lugar, hay dos tipos de objetos que comentaré, los tipos de valor y servicio.
Los tipos de servicio nunca deberían tener establecedores, las dependencias que requieran no deberían ser obtenibles. La mejor manera de pasar dependencias es a través de un constructor o una fábrica de esa manera, todas las instancias están completamente formadas desde el principio, así de simple.
Los tipos de valor también deben ser inmutables, por otro lado, hay momentos en que esto no es práctico, como un ORM, o alguna otra asignación, como de un widget a un objeto. Todos los demás tipos de valores que se pasan por el sistema de una capa o parte a otra deben ser inmutables y no deben tener configuradores.
fuente
Un Getter / Setter está justificado como cualquier otro método público está justificado. La justificación se debe principalmente a que queremos proporcionar una interfaz con el mundo exterior que defina cómo nuestra clase interactúa con otras clases. Hacemos esto principalmente porque queremos reducir el acoplamiento entre entidades separadas. Reducir el acoplamiento es bueno por muchas razones:
fuente
Sí, getters and setters es un antipatrón en la programación orientada a objetos y nunca debe usarse: http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html . En pocas palabras, no encajan en el paradigma orientado a objetos porque lo alientan a tratar un objeto como una estructura de datos. Lo cual es un gran error.
fuente
Espero que cualquier cosa que el IDE desarrollado por la compañía que desarrolla su lenguaje de programación genere automáticamente no viole los "Principios de Orientación de Objetos".
Dicho esto, cada vez que tenga una variable de ámbito público, use un getter y un setter y estará dorado. Me parece ser el elemento necesario del principio de encapsulación extremadamente orientado a objetos, incluso si solo parece un montón de código basura.
La razón para usarlos es que la encapsulación adecuada aún puede tener lugar y siempre y cuando haya abstraído la capa que le permite a la persona que hace el mono sentir su objeto, puede quitarlo sin que él lo sepa.
Baste decir que una casa dividida no puede sostenerse, uno de los inquilinos de OO no se volverá contra sí mismo y no puede servir tanto la encapsulación como la optimización prematura.
fuente
Pensé que tendríamos más respuestas habituales aquí?
Getters y setters son en general extremadamente OOP (cualquiera que diga algo más está mal, así de simple).
Aunque debe recordar no ser demasiado ingeniero, nunca haga un getter o setter que no sea necesario. Cualquier información que no vaya a utilizar en otra clase para la que no debería tener ningún captador o definidor.
Sin embargo, la razón por la que no hace públicos los campos y en su lugar tiene captadores y establecedores es principalmente:
No es posible realizar pruebas adecuadas mediante el uso de campos. Getters / setters son mucho mejores en ese sentido.
Es imposible usar correctamente los campos en una configuración de programación en tiempo real. Getters / setters sincronizados es el camino a seguir.
El tema de la interfaz (ya explicado, así que no lo haré).
Es más fácil de usar cuando se reutiliza correctamente el sistema.
Es mucho más difícil saber qué clases están usando su clase y qué se romperá si cambia un campo que un captador / establecedor.
Por lo tanto, la única vez que usa un campo público en lugar de un captador / definidor es cuando no realiza un proyecto oficial, sino que lo hace por diversión y no puede molestarse con el captador / definidor.
fuente