¿Está completamente en contra de la forma Java de crear estructuras como objetos?
class SomeData1 {
public int x;
public int y;
}
Puedo ver una clase con accesores y mutadores más parecidos a Java.
class SomeData2 {
int getX();
void setX(int x);
int getY();
void setY(int y);
private int x;
private int y;
}
La clase del primer ejemplo es notablemente conveniente.
// a function in a class
public int f(SomeData1 d) {
return (3 * d.x) / d.y;
}
Esto no es tan conveniente.
// a function in a class
public int f(SomeData2 d) {
return (3 * d.getX()) / d.getY();
}
Respuestas:
Este es un tema comúnmente discutido. El inconveniente de crear campos públicos en objetos es que no tiene control sobre los valores que se le asignan. En los proyectos grupales donde hay muchos programadores que usan el mismo código, es importante evitar los efectos secundarios. Además, a veces es mejor devolver una copia del objeto de campo o transformarlo de alguna manera, etc. Puede burlarse de tales métodos en sus pruebas. Si crea una nueva clase, es posible que no vea todas las acciones posibles. Es como la programación defensiva: algún día los captadores y los establecedores pueden ser útiles, y no cuesta mucho crearlos / usarlos. Entonces a veces son útiles.
En la práctica, la mayoría de los campos tienen captadores y establecedores simples. Una posible solución se vería así:
Actualización: es muy poco probable que se agregue soporte de propiedad en Java 7 o tal vez alguna vez. Otros lenguajes JVM como Groovy, Scala, etc., ahora son compatibles con esta función. - Alex Miller
fuente
=
, lo que en mi opinión hace que el código sea más limpio.x
s que son dos cosas diferentes, no es una buena idea. En mi humilde opinión, es una sugerencia pobre, ya que podría conducir a la confusión de los lectores humanos. Principio básico: no haga que un lector haga una doble toma; haz que sea obvio lo que estás diciendo: usa diferentes nombres para diferentes entidades. Incluso si la diferencia es simplemente anteponer un guión bajo. No confíe en la puntuación circundante para diferenciar las entidades.Parece que muchas personas de Java no están familiarizadas con las Pautas de codificación de Sun Java que dicen que es bastante apropiado usar una variable de instancia pública cuando la clase es esencialmente una "Estructura", si Java admite "estructura" (cuando no hay comportamiento).
La gente tiende a pensar que los getters y setters son la forma de Java, como si estuvieran en el corazón de Java. Esto no es asi. Si sigue las Pautas de codificación de Sun Java, utilizando variables de instancia pública en situaciones apropiadas, en realidad está escribiendo un código mejor que saturarlo con captadores y establecedores innecesarios.
Convenios de código Java de 1999 y aún sin cambios.
10.1 Proporcionar acceso a las variables de instancia y clase
No haga pública ninguna instancia o variable de clase sin una buena razón. A menudo, las variables de instancia no necesitan establecerse u obtenerse explícitamente, lo que a menudo ocurre como un efecto secundario de las llamadas a métodos.
Un ejemplo de variables de instancia pública apropiadas es el caso donde la clase es esencialmente una estructura de datos, sin comportamiento. En otras palabras, si hubiera utilizado una estructura en lugar de una clase (si Java admite estructura), entonces es apropiado hacer públicas las variables de instancia de la clase .
http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177
http://en.wikipedia.org/wiki/Plain_old_data_structure
http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28
fuente
Use el sentido común realmente. Si tienes algo como:
Entonces tiene poco sentido envolverlos en captadores y colocadores. Nunca vas a almacenar una coordenada x, y en píxeles enteros de ninguna otra manera. Getters y setters solo te retrasarán.
Por otro lado, con:
Es posible que desee cambiar la forma en que se calcula un saldo en algún momento en el futuro. Esto realmente debería usar getters y setters.
Siempre es preferible saber por qué está aplicando buenas prácticas, para saber cuándo está bien doblar las reglas.
fuente
(-5, -5)
que no sea una buena idea. :-)Para abordar los problemas de mutabilidad, puede declarar xey como final. Por ejemplo:
El código de llamada que intenta escribir en estos campos obtendrá un error de tiempo de compilación de "el campo x se declara final; no se puede asignar".
El código del cliente puede tener la comodidad de 'mano corta' que describiste en tu publicación
fuente
case
expresión que hace referencia a dicho campo de instancia, obtuveCase expressions must be constant expressions
. ¿Cuál es la forma de evitar esto? ¿Cuál es el concepto idiomático aquí?No utilizar
public
camposNo use
public
campos cuando realmente quiera ajustar el comportamiento interno de una clase. Tomajava.io.BufferedReader
por ejemplo. Tiene el siguiente campo:skipLF
se lee y se escribe en todos los métodos de lectura. ¿Qué sucede si una clase externa que se ejecuta en un hilo separado modifica maliciosamente el estado deskipLF
en medio de una lectura?BufferedReader
Definitivamente se volverá loco.Usa
public
camposTome esta
Point
clase por ejemplo:Esto haría que calcular la distancia entre dos puntos sea muy doloroso de escribir.
La clase no tiene ningún comportamiento que no sea getters y setters simples. Es aceptable usar campos públicos cuando la clase representa solo una estructura de datos, y no tiene, y nunca tendrá un comportamiento (los captadores y definidores delgados no se consideran comportamiento aquí). Se puede escribir mejor de esta manera:
¡Limpiar!
Pero recuerde: no solo su clase debe estar ausente de comportamiento, sino que tampoco debe tener ninguna razón para tener un comportamiento en el futuro.
(Esto es exactamente lo que describe esta respuesta . Para citar "Convenciones de código para el lenguaje de programación Java: 10. Prácticas de programación" :
Entonces la documentación oficial también acepta esta práctica.)
Además, si está seguro de que los miembros de la
Point
clase anterior deben ser inmutables, puede agregar unafinal
palabra clave para aplicarla:fuente
Por cierto, la estructura que está dando como ejemplo ya existe en la biblioteca de clases base de Java como
java.awt.Point
. Tiene x e y como campos públicos, compruébelo usted mismo .Si sabe lo que está haciendo, y otros en su equipo lo saben, entonces está bien tener campos públicos. Pero no debe confiar en él porque pueden causar dolores de cabeza como en los errores relacionados con los desarrolladores que usan objetos como si fueran estructuras asignadas a la pila (los objetos java siempre se envían a los métodos como referencias y no como copias).
fuente
public final
campo, como en la respuesta de Brian, o teniendo un captador público, pero sin setter público. Es decir, si uno usa campos o accesores es irrelevante.Re: aku, izb, John Topley ...
Cuidado con los problemas de mutabilidad ...
Puede parecer sensato omitir getters / setters. En realidad, puede estar bien en algunos casos. El verdadero problema con el patrón propuesto que se muestra aquí es la mutabilidad.
El problema es una vez que pasa una referencia de objeto que contiene campos públicos no finales. Cualquier otra cosa con esa referencia es libre de modificar esos campos. Ya no tienes ningún control sobre el estado de ese objeto. (Piense qué pasaría si las cadenas fueran mutables).
Se pone mal cuando ese objeto es una parte importante del estado interno de otro, acaba de exponer la implementación interna. Para evitar esto, se debe devolver una copia del objeto. Esto funciona, pero puede causar una presión masiva de GC de toneladas de copias de un solo uso creadas.
Si tiene campos públicos, considere hacer que la clase sea de solo lectura. Agregue los campos como parámetros al constructor y marque los campos como finales. De lo contrario, asegúrese de no exponer el estado interno y, si necesita construir nuevas instancias para un valor de retorno, asegúrese de que no se invoque excesivamente.
Ver: " Java efectivo " por Joshua Bloch - Artículo # 13: Favorecer la inmutabilidad.
PD: También tenga en cuenta que todas las JVM en estos días optimizarán el método getMethod si es posible, lo que dará como resultado una sola instrucción de lectura de campo.
fuente
He intentado esto en algunos proyectos, en la teoría de que los captadores y los creadores abarrotan el código con un desorden semántico sin sentido, y que otros lenguajes parecen funcionar bien con la ocultación de datos basada en convenciones o la división de responsabilidades (por ejemplo, python).
Como otros han señalado anteriormente, hay 2 problemas con los que te encuentras y no son realmente reparables:
Y este es el mejor de los casos de trabajar completamente en un proyecto privado autónomo. Una vez que exporta todo a una biblioteca de acceso público, estos problemas serán aún mayores.
Java es muy detallado, y esto es algo tentador. No lo hagas
fuente
Si la forma Java es la forma OO, entonces sí, crear una clase con campos públicos rompe los principios en torno a la ocultación de información que dicen que un objeto debe administrar su propio estado interno. (Por lo tanto, como no solo te estoy diciendo jerga, un beneficio de ocultar información es que el funcionamiento interno de una clase está oculto detrás de una interfaz; digamos que querías cambiar el mecanismo por el cual tu clase struct salvó uno de sus campos, probablemente necesitará regresar y cambiar cualquier clase que use la clase ...)
Tampoco puede aprovechar el soporte para las clases que cumplen con los nombres de JavaBean, lo que perjudicará si decide, por ejemplo, usar la clase en una página JavaServer que está escrita usando Expression Language.
El artículo de JavaWorld Por qué los métodos Getter y Setter son malos también puede ser de su interés al pensar cuándo no implementar métodos de acceso y mutadores.
Si está escribiendo una pequeña solución y desea minimizar la cantidad de código involucrado, la forma Java puede no ser la correcta, supongo que siempre depende de usted y del problema que está tratando de resolver.
fuente
No hay nada malo con ese tipo de código, siempre que el autor sepa que son estructuras (o transbordadores de datos) en lugar de objetos. Muchos desarrolladores de Java no pueden distinguir entre un objeto bien formado (no solo una subclase de java.lang.Object, sino un objeto verdadero en un dominio específico) y una piña. Ergo, terminan escribiendo estructuras cuando necesitan objetos y viceversa.
fuente
El problema con el uso del acceso de campo público es el mismo problema que con el uso de un método nuevo en lugar de un método de fábrica: si cambia de opinión más adelante, todas las llamadas existentes se rompen. Entonces, desde el punto de vista de la evolución de la API, generalmente es una buena idea morder la viñeta y usar getters / setters.
Un lugar al que voy hacia el otro lado es cuando controlas fuertemente el acceso a la clase, por ejemplo, en una clase estática interna utilizada como estructura de datos interna. En este caso, podría ser mucho más claro usar el acceso de campo.
Por cierto, según la afirmación de e-bartek, es muy poco probable que la OMI indique que se agregará soporte de propiedad en Java 7.
fuente
Con frecuencia uso este patrón cuando construyo clases internas privadas para simplificar mi código, pero no recomendaría exponer dichos objetos en una API pública. En general, cuanto más frecuentemente pueda hacer que los objetos en su API pública sean inmutables, mejor, y no es posible construir su objeto 'estructurado' de una manera inmutable.
Por otro lado, incluso si estuviera escribiendo este objeto como una clase interna privada, todavía proporcionaría un constructor para simplificar el código para inicializar el objeto. Tener que tener 3 líneas de código para obtener un objeto utilizable cuando se hace es simplemente desordenado.
fuente
Una pregunta muy antigua, pero déjame hacer otra pequeña contribución. Java 8 introdujo expresiones lambda y referencias de métodos. Las expresiones lambda pueden ser referencias de métodos simples y no declarar un cuerpo "verdadero". Pero no puede "convertir" un campo en una referencia de método. Así
no es legal, pero
es.
fuente
data -> data.x
, lo que sigue siendo razonableNo veo el daño si sabes que siempre será una estructura simple y que nunca querrás atribuirle un comportamiento.
fuente
Esta es una pregunta sobre el diseño orientado a objetos, no el lenguaje Java. En general, es una buena práctica ocultar los tipos de datos dentro de la clase y exponer solo los métodos que forman parte de la API de la clase. Si expone los tipos de datos internos, nunca podrá cambiarlos en el futuro. Si los oculta, su única obligación para con el usuario son los tipos de devolución y argumento del método.
fuente
Aquí creo un programa para ingresar el nombre y la edad de 5 personas diferentes y realizar una selección (edad). Usé una clase que actúa como una estructura (como el lenguaje de programación C) y una clase principal para realizar la operación completa. A continuación estoy proporcionando el código ...
El código anterior es libre de errores y probado ... Simplemente cópielo y péguelo en su IDE y ... ¿Sabes y qué? :)
fuente
Puede crear una clase simple con campos públicos y sin métodos en Java, pero sigue siendo una clase y aún se maneja sintácticamente y en términos de asignación de memoria como una clase. No hay forma de reproducir genuinamente estructuras en Java.
fuente
En algún momento uso esa clase, cuando necesito devolver múltiples valores de un método. Por supuesto, dicho objeto es de corta duración y con una visibilidad muy limitada, por lo que debería estar bien.
fuente
Como con la mayoría de las cosas, existe la regla general y luego hay circunstancias específicas. Si está haciendo una aplicación cerrada y capturada para saber cómo se va a usar un objeto determinado, puede ejercer más libertad para favorecer la visibilidad y / o la eficiencia. Si está desarrollando una clase que será utilizada públicamente por otros más allá de su control, entonces inclínese hacia el modelo getter / setter. Como con todas las cosas, solo usa el sentido común. A menudo está bien hacer una ronda inicial con públicos y luego cambiarlos a getter / setters más tarde.
fuente
La programación orientada a aspectos le permite atrapar asignaciones o recuperaciones y adjuntarles lógica de interceptación, lo que propongo es la forma correcta de resolver el problema. (La cuestión de si deberían ser públicas o protegidas o protegidas por paquetes es ortogonal).
Por lo tanto, comienza con campos no interceptados con el calificador de acceso correcto. A medida que crecen los requisitos de su programa, adjunta lógica para quizás validar, hacer una copia del objeto que se devuelve, etc.
La filosofía getter / setter impone costos en una gran cantidad de casos simples donde no son necesarios.
Si el estilo de aspecto es más limpio o no es algo cualitativo. Me resultaría fácil ver solo las variables en una clase y ver la lógica por separado. De hecho, la razón de ser de la programación orientada a Apect es que muchas preocupaciones son transversales y compartimentarlas en el cuerpo de la clase en sí no es ideal (el registro es un ejemplo: si desea iniciar sesión, todo lo que Java desea que haga) escribe un montón de captadores y mantenlos sincronizados, pero AspectJ te permite una frase).
El tema de IDE es una pista falsa. No es tanto la tipificación como la lectura y la contaminación visual que surge de get / sets.
Las anotaciones parecen similares a la programación orientada a aspectos a primera vista, sin embargo, requieren que enumere exhaustivamente los recortes de puntos adjuntando anotaciones, a diferencia de una especificación concisa de corte de punto similar a un comodín en AspectJ.
Espero que el conocimiento de AspectJ evite que las personas se instalen prematuramente en lenguajes dinámicos.
fuente