2010-06-25 10 views
10

Por lo general, JavaPractices.com es un buen sitio con una buena idea, pero este me preocupa: JavaBeans are bad.¿Son Java Beans como mal diseño de clases de almacenamiento de datos?

El artículo cita varios motivos, principalmente que el término JavaBean significa "Un Java Bean es un componente de software reutilizable que se puede manipular visualmente en una herramienta de creación". no almacenamiento de datos, viola ciertos patrones, y es más complejo.

Ahora puedo estar de acuerdo con el último, pero en mi opinión JavaBeans en una lista tiene mucho más sentido que los mapas anidados. El artículo afirma que los marcos de mapeo de bases de datos deben llamar a los constructores, no a los métodos * establecidos, y el objeto debe ser inmutable. En mi mente, sin embargo, llamar a los métodos set * cuando intentas construir un objeto es más fácil de leer que new MappedObject("column1", "column2", "yet another column", "this is stupid");

También uso la clase de estilo JavaBean para otras cosas además de la asignación de bases de datos, por ejemplo, para un bot IRC, tener un objeto por usuario eso se actualiza con varias cosas. No quiero crear un nuevo objeto cada vez que se da nueva información, quiero agregarlo a uno existente.

Así que mi pregunta: ¿El uso de JavaBeans para el almacenamiento de datos es una mala práctica y debería evitarse, o es perfectamente seguro?

+10

JavaBeans no representa tanto un patrón como un lenguaje completo antipatrón. –

+3

puede usar un generador para obtener los beneficios de la inmutabilidad y evitar el constructor súper largo. –

+6

Considera aprender sobre el patrón de construcción. http://en.wikipedia.org/wiki/Builder_pattern. – CoolBeans

Respuesta

19

Parece que estás malinterpretando el texto.

Ahora estoy de acuerdo con la última, pero en JavaBeans de mi ojo en una lista hace mucho más sentido que los mapas anidados

El texto no menciona mapas anidados como alternativa (yiack)

... deben llamar a los constructores, no ajustarse * métodos, y el objeto debe ser inmutable

Esta es una buena práctica, especialmente útil cuando se trata con hilos.

Pero no podemos decir que el uso de los emisores es baaad o bien, sobre todo cuando un solo hilo está utilizando el objeto. Eso es perfectamente seguro.

No quiero crear un nuevo objeto cada vez que se da nueva información, quiero agregarlo a uno existente.

Eso está bien, siempre y cuando se controle el objeto no existe ningún problema con esto, algunos otros pueden encontrar más fácil simplemente crear un nuevo objeto.

¿Está utilizando JavaBeans para el almacenamiento de datos una mala práctica y debe evitarse, o es perfectamente seguro?

No, no es una mala práctica. No es perfectamente seguro tampoco. Depende de la situación.

El problema con los objetos mutables (no con JavaBeans per se) es utilizar diferentes subprocesos para acceder a ellos.

Tiene que sincronizar el acceso para evitar que un hilo modifique el objeto mientras que otro está accediendo a él.

Los objetos inmutables no tienen este problema, porque, .. bien, no pueden cambiar, y por lo tanto, no tiene que sincronizar nada.

Para asegurarte de que un objeto es inmutable, debes declarar tus atributos como definitivos.

class MyBean { 
    private final int i; 
} 

Si desea asignar un valor razonable para MyBean.i tiene que especificar en el constructor:

public MyBean(int i) { 
    this.i = i; 
} 

Puesto que la variable es definitiva, no se puede utilizar un regulador. Solo puede proporcionar un getter.

Esto es perfectamente seguro para subprocesos y lo mejor es que no tiene que sincronizar el acceso, porque si dos subprocesos intentan obtener el valor de i, ambos verán siempre el valor asignado en la creación de instancias. no tiene que sincronizar nada

No es una mala práctica o una buena práctica.Debemos tener que trabajar con un solo hilo, incluso en entornos de subprocesos múltiples como servlets.

Si en el futuro hay que hacer frente a múltiples aplicaciones de hilo, es posible considerar el uso de un JavaBean inmutable;)

Por cierto, la alternativa de crear habas inmutables, y aún así proporcionar un montón de emisores está utilizando Builders como :

Employee e = new EmployeeBuilder() 
        .setName("Oscar") 
        .setLastName("Reyes") 
        .setAge(0x1F) 
        .setEmployeeId("123forme") 
        .build(); 

¿Qué se ve muy similar a la setXyz regular utilizada en los granos regulares con el beneficio de la utilización de los datos inmutables.

Si necesita cambiar un valor, se puede utilizar un método de clase:

Employee e = Employee.withName(e, "Mr. Oscar"); 

que toma el objeto existente, y copiar todos los valores, y establecer una nueva ....

public static EmployeeWithName(Employee e , String newName){ 
     return new Employee(newName, e.lastName, e.age, e.employeeId); 
    } 

Pero, de nuevo, en un solo modelo de hilo es perfectamente seguro usar getters/setters.

PD Lo recomiendo encarecidamente que compre este libro: Effective Java. Nunca te arrepentirás, y tendrás información para juzgar mejores artículos como el que se cita.

+0

+1 por buen contenido. Hablé de mapas anidados porque utilizo frijoles para otras cosas además de las filas de la base de datos, los objetos de usuario en evolución de IE. Sin embargo, dado que ambos están evolucionando, no estoy seguro de que la ruta inmutable, aunque tenga beneficios, sea la mejor aquí, ya que si quería cambiar el objeto, aún tengo problemas de sincronización + tratando de reemplazar el objeto existente. – TheLQ

+0

@ Lord.Quackstar Sí, pero la mayoría de las veces el hilo individual es lo suficientemente bueno, y los beans Java no son un mal patrón ni nada. Ellos son solo una alternativa. – OscarRyz

+0

Una cosa que también podría considerar sería tener un método toBuilder para cualquier bean dado, por lo que podría convertir cualquier bean en un generador, establecer algunos campos y luego reconstruir el objeto como un nuevo objeto. Entonces podría hacer employee = employee.toBuilder(). SetName ("Mary Poppins"). Build(); y eso te daría algo de semi-mutabilidad. –

0

Es perfectamente seguro, y mucho más preferible que anidados sin fin java.util.Map. Obtiene seguridad de tipo, código más fácil de entender y evita que su código termine en The Daily WTF. Tenga en cuenta que la implementación debe segregarse: no mezcle demasiada lógica (más allá de la simple validación) en sus clases de almacenamiento de datos. Usted debe leer sobre POJOs

3

"El patrón JavaBeans tiene serias desventajas." — Joshua Bloch, Effective Java

Yo amo a los chicos. Tomar citas arbitrarias fuera de contexto ya es motivo para que no confíe en ese artículo.

Por cierto, el libro referido (Effective Java) tiene una amplia discusión sobre ambos modelos, sus ventajas, desventajas y alternativas. Quizás quieras revisarlo. Pero no hay nada inherentemente malo con JavaBeans, solo que a veces no son la mejor opción.

Editar: Véase el punto 2 ("considerar un constructor cuando se enfrentan a muchos parámetros del constructor") en Effective Java en Google Books: http://books.google.com/books?id=ka2VUBqHiWkC&lpg=PP1&pg=PA11#v=onepage&q&f=false

+0

Acepto que los argumentos en el artículo son muy débiles, basados ​​en citas tomadas fuera de contexto y el artículo no propone una alternativa que sea claramente mejor. En otras palabras, @ Lord.Quackstar: no creas nada de lo que lees en un artículo al azar en Internet a su valor nominal. – Jesper

0

las intenciones de este artículo son bien intencionadas, pero en la práctica evitando los granos y setters es difícil de mantener. Por ejemplo, tener frameworks usando constructores no es posible en muchos casos dado que los nombres son usualmente la característica de identificación, y los nombres de parámetros de método/constructor no se mantienen en el archivo .class. (Aunque hay al menos un library para evitar esto.)

Los setters son la mejor alternativa, no como OO "puro", pero son una gran conveniencia para los constructores y funcionan bien en la práctica.

Las pruebas de Whem comienzan a fallar debido a los granos "malos" de java, entonces lo reconsideraré como motivo de preocupación. Pero no he visto eso hasta ahora. La única vez que diría que probablemente sean inapropiadas es compartir beans en código multiproceso, ya que sincronizar el estado mutable compartido es complicado. Aléjate de eso y los frijoles están bien.

+0

¿Qué considerarías un "grano de java malo"? – TheLQ

+0

Lo "malo" era que me estaba burlando del título del artículo, no creo que sean intrínsecamente malos, pero como todos los patrones, se puede abusar de ellos para convertirlos en un antipatrón. Tal vez, en algunos casos, los frijoles pueden producir un desacoplamiento innecesario entre el comportamiento y los datos, o donde el eliminador/eliminador habitual de una sola línea se haría mejor como un cálculo más rico. Y si solo las propiedades fueran un concepto de primera clase, entonces podríamos construir sobre el patrón sin la necesidad de cadenas (nombres de propiedades) y reflexión ... – mdma

+0

"Entre instanciar la clase y establecer la propiedad final, tiene un objeto que está internamente -consistente o inutilizable, "http://stackoverflow.com/a/3122912/262852 ese es el problema en pocas palabras. – Thufir

2

La razón principal para evitar setters es la inmutabilidad. Codifique la inmutabilidad por adelantado y evitará cualquier problema de enhebrado alrededor de esos objetos.

Si usted termina con un constructor que lee

nueva persona ("parámetro 1", "PARAM 2", "PARAM 3", "parámetro 4", "PARAM 5", "parámetro 6", "param 7", "param 8")

, entonces su objeto es demasiado complicado. Necesitará objetos de parámetros (vea el libro de refactorización de Martin Fowler).

Defina el código de forma defensiva al principio y las personas que se acerquen y mantengan su código le agradecerán (bien) o lo maldecirán (porque no pueden ser flojos y simplemente mutar objetos).

Cuando necesite cambiar el objeto, agregue un constructor de copia (es decir, método de clonación). Las JVM modernas lidian con esto de manera fácil y rápida y hay poca penalización de velocidad. También le facilita las cosas a Hotspot y al GC.

5

Mi objeción al uso de JavaBeans como clases de almacenamiento de datos es que permiten objetos con estado incoherente. En el caso de uso típico para tales beans, tiene los siguientes pasos:

  • instanciar la clase;
  • establece la primera propiedad;
  • establece la segunda propiedad;
  • ...
  • establece la propiedad final;
  • usa la instancia del objeto.

Ahora su clase está lista para usar. Entonces, ¿cuál es el problema aquí? Entre instanciar la clase y establecer la propiedad final, tiene un objeto que está en un estado incoherente o inutilizable internamente, pero no hay nada que le impida usarlo accidentalmente.Prefiero un sistema en el que la clase se encuentre automáticamente en un estado consistente y utilizable en la creación de instancias. Por esta razón, prefiero pasar todo el estado inicial en el constructor o, si dicho estado inicial es demasiado complicado, pasar el estado inicial en forma de un mapa o conjunto hash o similar. El escenario de caso de uso es ahora:

  • (Opcional: configurar un parámetros de objeto);
  • instanciar la clase;
  • usa la instancia del objeto.

En ningún punto de este flujo de trabajo es posible que accidentalmente empiece a usar un objeto con un estado incoherente. Si utilizo un objeto de parámetros, no se usa directamente para nada y su contenido se verificará al crear una instancia de mi clase principal. La clase principal en sí, al regresar de la instanciación, me dará una instancia de objeto que es de uso inmediato.

Este tipo de configuración es mejor para objetos más simples, por supuesto. Para objetos más complicados con cosas como propiedades opcionales, etc., querrás ir un paso más allá y usar algo parecido al patrón de Constructor que otros te han señalado. Los constructores son agradables cuando tienes escenarios más complicados, IMO, pero para una parametrización más simple y más sencilla, basta con usar argumentos de constructor o un objeto de parámetros de algún tipo es más que suficiente.

Cuestiones relacionadas