java - formulario - spring form form action
Mejores prácticas para la inicialización del árbol de objetos de Spring MVC form-backing (4)
He seguido el método de Factory (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 Person 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 ...
Si tengo un objeto de formulario de respaldo que tiene un árbol de objetos complicado, por ejemplo, una persona que tiene un objeto de información de contacto que tiene un objeto de dirección que tiene un montón de cadenas, parece que el objeto debe completarse por completo con el componente objetos 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.
Primera pregunta, por supuesto: ¿estoy en lo correcto en mis suposiciones anteriores? Parece que si intento enlazar con person.contactInfo.homeAddress.street y no hay ContactInfo, obtengo una excepción de puntero nulo.
Segundo, ¿cuál es la mejor manera de inicializar mi objeto? Puedo pensar en un par de enfoques. Una es 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();
}
Etcétera.
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 en particular no tiene una dirección en la base de datos, el objeto aún tendrá una Dirección), pero esto significará 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?
Por lo general, me aseguro de que los objetos estén completamente inicializados: hace que usar el objeto sea mucho más sencillo y evita dispersar comprobaciones nulas en todo el 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 realmente se va a usar, es decir, cuando se llama al getter y solo si es nulo.
En términos de carga desde 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 de 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 pretende iterar y para cada uno de los padres que desea iterar sobre sus elementos secundarios. Obviamente, el rendimiento sería desagradable porque estarías haciendo +1 llamadas al DB cuando en realidad podrías hacerlo con 2 llamadas.
Supongo que estás hablando de algo como < form:input path="person.contactInfo.homeAddress.street"/>
? No está claro para mí, pero supongo que estoy en lo cierto :):
1) Sí, cuando escribe person.contactInfo.homeAddress.street
, lea 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 miembros 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 te obligan a crear una Persona dos veces ... pero puedo estar cansado;)
Llámelo exagerado si lo desea, pero lo que realmente terminamos haciendo fue crear una fábrica genérica que tomará cualquier objeto y usará la reflexión para (recursivamente) encontrar todas las propiedades nulas y crear una instancia de un objeto del tipo correcto. Hice esto usando Apache Commons BeanUtils.
De esta forma puede tomar un objeto que haya obtenido de varias fuentes (un DAO, deserialización de XML, lo que sea), pasarlo por esta fábrica y usarlo como objeto de respaldo de formularios sin preocuparse de que algo que necesite para el enlace pueda ser nulo.
Es cierto que esto significa crear instancias de las propiedades que puede que no necesitemos para un formulario determinado, pero en nuestro caso eso normalmente no se aplica.