2008-12-18 10 views
7

Si tengo un objeto de formulario que tiene un árbol de objetos complicado, por ejemplo, una persona que tiene un objeto de información de contacto que tiene un objeto Address que tiene un montón de cadenas - Parece que el objeto necesita estar completamente poblado con objetos componentes antes de que pueda enlazarlo. Entonces, si estoy creando una nueva Persona, necesito asegurarme de que tiene todos los objetos componentes llenos del bate, y si estoy recuperando una Persona de la base de datos, necesito asegurarme de que los objetos que no están poblado de la base de datos se llena con objetos vacíos.Mejores prácticas para la inicialización del árbol de objetos MVC de Spring MVC

Primera pregunta, por supuesto, ¿estoy en lo correcto en mis suposiciones? Parece que si intento enlazar con person.contactInfo.homeAddress.street y no hay ContactInfo, obtengo una excepción de puntero nulo.

En segundo lugar, ¿cuál es la mejor manera de inicializar mi objeto. Puedo pensar en un par de enfoques. Uno es para inicializar todos los objetos miembros en la declaración:

public class Person { 
    String name; 
    ContactInfo contactInfo = new ContactInfo(); 
    //getters, setters, etc. 
} 

public class ContactInfo { 
    String phone; 
    Address homeAddress = new Address(); 
} 

y así sucesivamente.

Otro enfoque es tener una PersonFactory que inicialice todo (o tener un método de fábrica Person.getInstance que inicialice todo).

En el caso de recuperar una Persona de la base de datos, el primer enfoque resolverá el problema (es decir, si esta persona no tiene una dirección en la base de datos, el objeto todavía tendrá una Dirección), pero esto significa crear cada objeto dos veces. No estoy seguro de cómo manejar esto de otra manera, excepto para hacer que el DAO llene explícitamente todo, incluso si no se ha recuperado nada de la base de datos. O para dar a la fábrica un método para revisar el objeto y "completar" todo lo que falta.

Sugerencias?

+0

¿Hay alguna manera de proporcionar un método de fábrica para los frijoles de forma de respaldo? – Antoniossss

Respuesta

4

Llámelo exagerado si lo desea, pero lo que realmente terminamos haciendo fue crear una fábrica genérica que tomará cualquier objeto y usa la reflexión para (recursivamente) encontrar todas las propiedades nulas e instanciar un objeto del tipo correcto. Hice esto usando Apache Commons BeanUtils.

De esta forma puede tomar un objeto que pueda haber obtenido de varias fuentes (un DAO, deserialización de XML, lo que sea), pasarlo a través de esta fábrica y usarlo como objeto de respaldo de formularios sin preocuparse de que algo la necesidad de encuadernación puede ser nula.

Es cierto que esto significa crear instancias de propiedades que puede que no necesitemos para un formulario determinado, pero en nuestro caso eso normalmente no se aplica.

+0

solo por curiosidad: para obtener su objetivo, ¿utiliza el método BeanUtils.cloneBean ??? Si no, ¿sería posible que muestres cómo? –

+0

No, no uso cloneBean. Brevemente, la situación podría ser, por ejemplo, que podría tener un objeto de contacto que tiene una propiedad de dirección que es nula. Necesito poner un nuevo objeto de Dirección allí. Así que uso PropertyDescriptor.getPropertyType() para obtener la clase de la propiedad, y luego uso Class.getConstructor(). NewInstance() para instanciarlo. La única complejidad es que, en algunos casos, el tipo de propiedad es una interfaz; en esos casos, para la aplicación que describí, confío en la convención de nomenclatura que utilizamos para las interfaces: si la interfaz es IAddress, la implementación es Dirección. –

1

Supongo que estás hablando de algo como < form:input path="person.contactInfo.homeAddress.street"/>? No está claro para mí, pero suponiendo que tengo razón :):

1) Sí, Cuando se escribe person.contactInfo.homeAddress.street, leer person.getContactInfo().getHomeAddress().getStreet(). Si los objetos ContactInfo, HomeAddress o Street son nulos, la invocación de uno de sus métodos genera una NullPointException.

2) Normalmente inicializo los objetos miembro en la declaración, al igual que en el fragmento de código. No veo el beneficio de la clase de fábrica para hacer el trabajo si los valores de inicialización son incondicionales. No veo claramente el problema donde se ve forzado a crear una Persona dos veces ... pero puedo estar cansado;)

+0

Si estoy recuperando material de la base de datos, la inicialización en la declaración creará un ContactInfo, que luego será reemplazado por otro ContactInfo creado por el DAO con datos en él. Así que habrá creado uno extra. –

3

En general, me aseguro de que los objetos estén completamente inicializados; hace que usar el objeto sea mucho más simple y evita dispersar verificaciones nulas a lo largo de su código.

En el caso que proporcione aquí probablemente coloque la inicialización en el getter para que el objeto secundario solo se cree una instancia cuando se va a usar realmente, es decir: cuando se llama al getter y solo si es nulo.

En términos de carga de la base de datos con relaciones uno-a-uno, normalmente me uniría y cargaría el lote. El impacto en el rendimiento suele ser mínimo, pero debe tener en cuenta que puede haber uno.

Cuando se trata de relaciones uno-a-muchos normalmente voy por la carga perezosa. Hibernate se encargará de esto, pero si está ejecutando el suyo, solo necesita una implementación personalizada de List que llame al DAO apropiado cuando se invoque cualquiera de los métodos relacionados con su contenido.

La única excepción a este comportamiento con las relaciones de uno a muchos es cuando tiene una lista de objetos principales sobre los que intenta iterar y para cada uno de los padres que desea iterar sobre sus elementos secundarios. Obviamente, el rendimiento sería malo porque estarías haciendo n + 1 llamadas al DB cuando en realidad podrías hacerlo con 2 llamadas.

+0

Gracias. Me gusta la idea de poner la inicialización en el getter; lo mejor de ambos mundos para mí. Lo probaré y lo marcaré como la "respuesta" si parece funcionar. Para colecciones, me gusta usar LazyList de Apache Commons. Le permite especificar una fábrica. –

+2

Adición al punto LazyList: resulta que Spring tiene una lista perezosa llamada AutoPopulatingList. –

1

He seguido el método de Fábrica (no soy partidario de usar una clase separada para él, para mí tiene más sentido tenerlo en un método estático, así que todo está en un solo lugar). Tengo algo así como -

public static Person getInstanceForContactInfoForm() { 
     ContactInfo contactInfo = ContactInfo.getInstanceForContactInfoForm(); 

     Person person = new Person(contactInfo); 
     // set whatever other properties you need for Person 
     // just enough to 1-render the form and 2-avoid any exceptions 
     return person; 
} 

Si estoy cargando la persona de la base de datos, tengo un método en la clase Persona llamado algo así como "initalizeForContactInfoForm" o algo así. Después de cargar la persona de la base de datos, llamaré a este método en la capa de servicio en el método invocado por el método Spring MVC que devuelve el objeto de respaldo de formulario.

No creo que esto sea realmente una convención, es solo un enfoque que cociné por mi cuenta. Realmente no veo cuáles son los inconvenientes, así que si alguien no está de acuerdo, por favor, hágamelo saber ...

+0

El inconveniente para nosotros es que con frecuencia usamos una instancia determinada como objeto de respaldo de formulario para formularios múltiples. Además, por supuesto, esto aumenta la sobrecarga de agregar un nuevo formulario o agregar nuevos campos a un formulario; ahora debe cambiar el objeto y el DAO además del formulario. –

Cuestiones relacionadas