Estructura como objetos en Java

195

¿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();
}
Chris de Vries
fuente
9
En lugar de campos mutables públicos, considere los campos inmutables públicos o los campos mutables locales del paquete. Cualquiera de los dos sería mejor en mi humilde opinión.
Peter Lawrey
Recuerde que, si bien los captadores y los establecedores son feos / detallados, eso es algo así como el corazón de Java. Es un lenguaje no conciso. Por otro lado, sin embargo, NUNCA debe escribir nada de eso, ya que eso es lo que su IDE hace por usted. En un lenguaje dinámico, debe escribir menos, pero debe escribir (generalmente, aunque los IDE pueden ayudar).
Dan Rosenstark
Irónicamente, si bien OO tiene sus puntos fuertes en términos de encapsulación, hay un precio que se debe pagar por la CPU y el almacenamiento. El recolector de basura (casi por completo) elimina la necesidad de preocuparse por cuándo se deben borrar las referencias a objetos. La tendencia actual está completando el círculo mediante el uso de estructuras similares a C fuera de montón. Esto es perfecto para soluciones de tipo de almacenamiento en caché, comunicaciones entre procesos, operaciones más rápidas con uso intensivo de memoria, menor GC o / h e incluso puede beneficiarse de un menor almacenamiento o / h para sus conjuntos de datos. Si sabes lo que estás haciendo, no harías esta pregunta ... ¡así que piénsalo de nuevo!
user924272
@ user924272: Re "La tendencia actual se está volviendo un círculo completo mediante el uso de estructuras similares a C fuera del montón". ¿Qué harías en Java, cómo? En mi humilde opinión, esta es un área donde Java está mostrando su edad ...
ToolmakerSteve
@ToolmakerSteve -Estoy viendo un círculo. No soy el unico. Empresas como Azul están de moda en la recolección de basura sin pausa. Java es viejo Cierto. ¿Ingenieros que detectan una debilidad y hacen algo al respecto, en lugar de gemir? ¡Merecen respeto! +10 a Azul de mi parte :-)
user924272

Respuestas:

62

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í:

public property String foo;   
a->Foo = b->Foo;

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

Bartosz Bierkowski
fuente
28
Eso es una lástima, me gustan las propiedades de estilo C # (que suena como lo que estás hablando)
Jon Onstott
2
Así que usa la sobrecarga ... private int _x; public void x (int value) {_x = value; } public int x () {return _x; }
Gordon
12
Prefiero poder usar =, lo que en mi opinión hace que el código sea más limpio.
Svish
66
@ T-Bull: Solo porque PUEDES tener dos xs 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.
ToolmakerSteve
2
@ToolmakerSteve: Ese "podría generar confusión" es el argumento más común y aún el más débil cuando se trata de defender el dogma de codificación (en oposición al estilo de codificación). Siempre hay alguien que PODRÍA confundirse por las cosas más simples. Siempre encontrará a alguien quejándose de que cometió un error después de permanecer despierto y codificar durante media semana o algo así y luego culpar al estilo de codificación engañoso. No dejo que eso cuente. Ese estilo es válido, obvio y mantiene limpio el espacio de nombres. Además, no hay entidades diferentes aquí, hay / una / entidad y algo de código repetitivo a su alrededor.
T-Bull
290

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

desarrollador.g
fuente
88
+1 Por tener una fuente autorizada. Todas las demás respuestas son personas que expresan sus opiniones como si fueran hechos.
ArtOfWarfare
1
Hay una especificación de Java Beans que es una forma estándar de la industria de acceder a las propiedades utilizando métodos get y set ... vea en.wikipedia.org/wiki/JavaBeans para obtener una descripción general.
user924272
44
@ user924272: ¿Cómo es relevante la especificación de Java Beans para esta respuesta, que analiza cuándo es apropiado usar "variables de instancia pública"? Si la especificación fuera una forma estándar de convertir automáticamente las variables de instancia en propiedades, ala C #, podría ser relevante. Pero no lo es, ¿verdad? Simplemente especifica el nombre de los captadores y establecedores repetitivos que tendrían que crearse, para hacer tal mapeo.
ToolmakerSteve
@ToolmakerSteve. Esta es una pregunta de Java. Además, la pregunta escapa a un problema común donde existe una especificación. Desde una perspectiva de la vieja escuela, es mucho más fácil depurar mutaciones de campo cuando hay una forma estándar de hacerlo: establecer un punto de interrupción en un setter. Esto probablemente se ha vuelto obsoleto con los depuradores modernos, sin embargo, me veo obligado a desaprobar las clases que directamente "perforan" objetos ... aunque esto está bien para aplicaciones más pequeñas, es un verdadero dolor de cabeza para aplicaciones más grandes y organizaciones grandes
user924272
223

Use el sentido común realmente. Si tienes algo como:

public class ScreenCoord2D{
    public int x;
    public int y;
}

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:

public class BankAccount{
    public int balance;
}

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.

izb
fuente
3
Estoy de acuerdo con esta respuesta y digo que puedes crear una clase con campos públicos siempre que los campos estén en negrita independientes entre sí. es decir, un campo no depende de otro. Esto puede ser bastante útil en muchos casos, para múltiples valores de retorno de una función, o para coordenadas polares. {ángulo, longitud} que van juntos pero no dependen el uno del otro de ninguna manera intrínseca.
Spacen Jasset
@SpacenJasset: FYI, no veo cómo sus ejemplos (valores de retorno múltiples; coordenadas polares) tienen alguna relación con el uso de campos públicos vs getter / setters. En el caso de valores de retorno múltiples, incluso podría ser contraproducente, porque podría decirse que la persona que llama solo debe OBTENER los valores devueltos, lo que argumenta a favor de los captadores públicos y los establecedores privados (inmutables). Esto también puede ser cierto para devolver coordenadas polares desde un objeto (x, y): considere los errores matemáticos ACUMULATIVOS, ya que los cambios en los componentes individuales de las coordenadas polares se convierten de nuevo a (x, y).
ToolmakerSteve
@SpacenJasset: Pero estoy de acuerdo con tu principio.
ToolmakerSteve
1
Tiene un punto válido, pero creo que lo de los píxeles es un mal ejemplo, ya que asegurarse de que el píxel esté dentro de la ventana (solo un ejemplo) es algo que alguien podría hacer y, además, dejar que alguien configure el píxel para (-5, -5)que no sea una buena idea. :-)
Horsey
50

Para abordar los problemas de mutabilidad, puede declarar xey como final. Por ejemplo:

class Data {
  public final int x;
  public final int y;
  public Data( int x, int y){
    this.x = x;
    this.y = y;
  }
}

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

public class DataTest {
    public DataTest() {
        Data data1 = new Data(1, 5);
        Data data2 = new Data(2, 4);
        System.out.println(f(data1));
        System.out.println(f(data2));
    }

    public int f(Data d) {
        return (3 * d.x) / d.y;
    }

    public static void main(String[] args) {
        DataTest dataTest = new DataTest();
    }
}
Brian
fuente
3
Gracias, una respuesta útil y concisa. Muestra cómo obtener el beneficio de la sintaxis de campo, cuando no se desea mutabilidad.
ToolmakerSteve
@ToolmakerSteve, gracias por los comentarios, muy apreciado.
Brian
Intenté usar instancias finales de una clase final con campos finales como "instancias" de estructura, pero en una caseexpresión que hace referencia a dicho campo de instancia, obtuve Case expressions must be constant expressions. ¿Cuál es la forma de evitar esto? ¿Cuál es el concepto idiomático aquí?
n611x007
1
Los campos finales siguen siendo referencias a objetos, que no son constantes, ya que se inicializarán cuando la clase se use por primera vez. El compilador no puede conocer el "valor" de las referencias de objeto. Las constantes se deben conocer al compilar.
Johan Tidén
1
+1 Respuesta realmente importante. La utilidad de las clases inmutables no puede subestimarse en mi opinión. Su semántica de "disparar y olvidar" hace que el razonamiento sobre el código a menudo sea más simple, especialmente en entornos multiproceso, donde pueden compartirse arbitrariamente entre subprocesos, sin sincronización.
TheOperator
11

No utilizar publiccampos

No use publiccampos cuando realmente quiera ajustar el comportamiento interno de una clase. Toma java.io.BufferedReaderpor ejemplo. Tiene el siguiente campo:

private boolean skipLF = false; // If the next character is a line feed, skip it

skipLFse 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 de skipLFen medio de una lectura? BufferedReaderDefinitivamente se volverá loco.

Usa publiccampos

Tome esta Pointclase por ejemplo:

class Point {
    private double x;
    private double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() {
        return this.x;
    }

    public double getY() {
        return this.y;
    }

    public void setX(double x) {
        this.x = x;
    }

    public void setY(double y) {
        this.y = y;
    }
}

Esto haría que calcular la distancia entre dos puntos sea muy doloroso de escribir.

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.getX() - a.getX(), 2) + Math.pow(b.getY() - a.getY(), 2));

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:

class Point {
    public double x;
    public double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));

¡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" :

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 en structlugar de una clase (si Java es compatible struct), entonces es apropiado hacer públicas las variables de instancia de la clase.

Entonces la documentación oficial también acepta esta práctica.)


Además, si está seguro de que los miembros de la Pointclase anterior deben ser inmutables, puede agregar una finalpalabra clave para aplicarla:

public final double x;
public final double y;
sampathsris
fuente
8

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).

Spoike
fuente
+1 Buena mención de un problema: una forma en que el resultado todavía NO es como una estructura C. Sin embargo, el problema que usted plantea acerca de los objetos java siempre como referencia, no mejora al crear un setter en lugar de tener un campo público de escritura (que es la esencia de la pregunta de OP: qué representación usar). Más bien, es un argumento a favor de NO HACER NADA. Es un argumento a favor de la INMUTABILIDAD. Lo que se puede hacer como un public finalcampo, 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.
ToolmakerSteve
8

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.

Mark Renouf
fuente
12
¿Cómo resuelve este problema un getter / setter? Todavía tiene una referencia, no tiene ninguna sincronización con las operaciones. Getters / setters no brindan protección en sí mismos.
he_the_great
1
Getters y setters pueden proporcionar sincronización si es necesario. También espera que los getters y setter hagan mucho más de lo que se especificó. Independientemente de esto, el problema de la sincronización aún se resuelve.
user924272
7

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:

  • Casi cualquier herramienta automatizada en el mundo de Java se basa en la convención getter / setter. Lo mismo para, como lo han señalado otros, etiquetas jsp, configuración de resortes, herramientas de eclipse, etc., etc. Luchar contra lo que sus herramientas esperan ver es una receta para largas sesiones de búsqueda en google tratando de encontrar esa forma no estándar de iniciar frijoles de primavera. Realmente no vale la pena.
  • Una vez que tenga su aplicación elegantemente codificada con cientos de variables públicas, es probable que encuentre al menos una situación en la que son insuficientes, donde absolutamente necesita inmutabilidad, o necesita desencadenar algún evento cuando se establece la variable, o desea lanzar una excepción en un cambio variable porque establece un estado de objeto en algo desagradable. Luego, se queda atrapado con las opciones poco envidiables entre abarrotar su código con algún método especial en todas partes donde se hace referencia directa a la variable, teniendo algún formulario de acceso especial para 3 de las 1000 variables en su aplicación.

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

Steve B.
fuente
Excelente discusión de los problemas de ir por el camino de los campos públicos. Una deficiencia definitiva de Java, que me molesta cuando tengo que volver a Java desde C # (que aprendí de los inconvenientes de Java aquí).
ToolmakerSteve
4

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.

brabster
fuente
1
+1 para el enlace al artículo "Por qué los métodos Getter y Setter son malos". Sin embargo, su respuesta habría sido más clara si señalara que AMBOS campos públicos Y captadores / establecedores públicos NO SON IGUALMENTE la forma de Java: como se explica en ese artículo, cuando sea posible, tampoco lo haga. En su lugar, proporcione a los clientes métodos específicos para lo que necesitan hacer, en lugar de reflejar la representación interna de la instancia. SIN EMBARGO, esto realmente no aborda la pregunta que se hace (cuál usar, para un caso simple de "estructura"), que es mejor respondida por developer.g, izb y Brian.
ToolmakerSteve
3

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.

luis.espinal
fuente
la piña me hace reír :)
Guillaume
Sin embargo, esta respuesta no dice nada sobre cuál es esa diferencia. La molestia de los desarrolladores no calificados no ayuda a esos desarrolladores a saber cuándo hacer una estructura y cuándo hacer una clase.
ToolmakerSteve
No dice nada sobre la diferencia porque su autor es consciente de la diferencia (él sabe qué es una entidad de estructura). El autor pregunta si el uso de estructuras es apropiado en un lenguaje OO, y yo digo que sí (dependiendo del dominio del problema). Si la pregunta era sobre qué hace que un objeto sea un objeto de dominio real, entonces tendría una pata para pararse en su argumento.
luis.espinal
Además, el único tipo de desarrollador no calificado que no debería saber la diferencia sería el que todavía está en la escuela. Esto es extremadamente fundamental, como saber la diferencia entre una lista vinculada y una tabla hash. Si una persona se gradúa con un título de software de 4 años sin saber cuál es un verdadero objeto, entonces esa persona no está cortada para esta carrera o debe regresar a la escuela y exigir un reembolso. Lo digo en serio.
luis.espinal
Pero para satisfacer su queja, le daré una respuesta (que tiene poco que ver con la pregunta original y que merece su propio hilo). Los objetos tienen comportamiento y estado encapsulado. Las estructuras no lo hacen. Los objetos son máquinas de estado. Las estructuras son solo para agregar datos. Si las personas quieren una respuesta más elaborada, son libres de crear una nueva pregunta donde podamos elaborarla al contenido de nuestros corazones.
luis.espinal
2

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.

Alex Miller
fuente
1
Esto es cierto, pero si está utilizando Java no es una preocupación, ya que puede refactorizar una base de código completa con un solo clic (Eclipse, Netbeans, probablemente VIM y Emacs también). Si ha optado por uno de sus amigos dinámicos, como Groovy, incluso una simple encapsulación podría hacer que lo arregle durante horas o días. Afortunadamente, tendría sus casos de prueba que le informarían ... cuánto más código tiene que arreglar.
Dan Rosenstark
2
Asume, por supuesto, que todos los usuarios están en su base de código, pero por supuesto, eso a menudo no es cierto. A menudo, ni siquiera es posible por varias razones no técnicas cambiar el código que podría estar en su propia base de código.
Alex Miller
2

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.

Kris Nuttycombe
fuente
2

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í

stream.mapToInt(SomeData1::x)

no es legal, pero

stream.mapToInt(SomeData2::getX)

es.

Lyubomyr Shaydariv
fuente
En este caso, puede usar data -> data.x, lo que sigue siendo razonable
James Kraus,
1

No veo el daño si sabes que siempre será una estructura simple y que nunca querrás atribuirle un comportamiento.

John Topley
fuente
1

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.

Jonathan
fuente
1

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 ...

import java.io.*;

class NameList {
    String name;
    int age;
}

class StructNameAge {
    public static void main(String [] args) throws IOException {

        NameList nl[]=new NameList[5]; // Create new radix of the structure NameList into 'nl' object
        NameList temp=new NameList(); // Create a temporary object of the structure

        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

        /* Enter data into each radix of 'nl' object */

        for(int i=0; i<5; i++) {
            nl[i]=new NameList(); // Assign the structure into each radix

            System.out.print("Name: ");
            nl[i].name=br.readLine();

            System.out.print("Age: ");
            nl[i].age=Integer.parseInt(br.readLine());

            System.out.println();
        }

        /* Perform the sort (Selection Sort Method) */

        for(int i=0; i<4; i++) {
            for(int j=i+1; j<5; j++) {
                if(nl[i].age>nl[j].age) {
                    temp=nl[i];
                    nl[i]=nl[j];
                    nl[j]=temp;
                }
            }
        }

        /* Print each radix stored in 'nl' object */

        for(int i=0; i<5; i++)
            System.out.println(nl[i].name+" ("+nl[i].age+")");
    }
}

El código anterior es libre de errores y probado ... Simplemente cópielo y péguelo en su IDE y ... ¿Sabes y qué? :)

Avik Kumar Goswami
fuente
0

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.

cblades
fuente
0

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.

PhiLho
fuente
0

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.

Evvo
fuente
0

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.

nigromante
fuente