2010-01-29 28 views
5

Si utilizo el patrón MVP con GWT, como en las mejores prácticas de la arquitectura GWT hablo desde Google I/O desde 2009, pero extendí la información en múltiples widgets, ¿cómo debería ser el objeto de valor? ser poblado?MVP y comunicación entre widgets GWT

Supongamos que tengo un EditPersonView/Presenter, un EditPetView/Presenter y un EditAddressView/Presenter y los dos últimos son widgets como parte de un panel en EditPersonView. Con estos tengo la clase siguiente:

class PersonDetails { 
    private PetDetails pet; 
    private AddressDetails addressDetails; 

    // ... 
} 

El PetDetails y variables de instancia AddressDetails se gestionan de sus homólogos del presentador. Cuando el usuario hace clic en el botón "Guardar" en EditPersonView, ¿cómo debe hacerse la comunicación entre los widgets para que PersonDetails esté lleno de información de sus widgets secundarios?

Respuesta

1

He enfrentado este mismo problema en algunas aplicaciones diferentes de GWT que he diseñado utilizando el enfoque de Ray Ryan. Mi solución preferida es crear un "objeto de sesión" de Singleton que almacene el estado de esa parte de la aplicación. En su ejemplo, podría tener este aspecto:

interface EditPersonSession { 

    void fetchPerson(PersonId id); 
    PersonDetails getCurrentPersonDetails(); 
    void updatePersonDetail(PersonDetail<?> detail); 
    void updatePetDetail(PetDetail<?> detail); 
    void updateAddressDetail(AddressDetail<?> detail); 
    void save(); 

} 

Los tres presentadores contienen una referencia al objeto de sesión (tal vez inyectado por Gin). Siempre que el usuario manipule la interfaz de usuario (vista), el presentador asociado con esa vista inmediatamente empuja el estado hacia el objeto de sesión compartido. Por ejemplo, en el interior EditAddressPresenter:

view.getStreetNameTextBox().addValueChangeHandler(new ValueChangeHandler() { 

    void onValueChange(ValueChangeEvent<String> event) { 
     editPersonSession.updateAddressDetail(new StreetNameAddressDetail(event.getValue())); 
    } 

} 

Cuando es el momento de guardar, el objeto de estado se le dice que guardar el estado al servidor. En este punto, el objeto de sesión tiene representaciones actualizadas de los datos y puede guardarlo todo de una vez. Así, en EditPersonPresenter:

view.getSaveButton().addClickHandler(new ClickHandler() { 

    void onClick(ClickEvent event) { 
     editPersonSession.save(); 
    } 

} 

De esta manera, los presentadores no necesita contener ninguna referencia a unos de otros, pero pueden enviar información consistente con el servidor. Si los presentadores necesitan saber cuándo se ha actualizado la información que muestran (ya sea por otros presentadores o por el servidor), el objeto de sesión puede notificarlos activando eventos en el bus de eventos (Singleton HandlerManager compartido). Los presentadores pueden extraer los PersonDetails más actuales del objeto de la sesión.

+0

Hmm ... Solución interesante. Lo que no me entusiasma es el hecho de que necesitaré registrar manejadores de cambios de valor para todos los elementos que pueden no obtener una representación instantánea del diálogo como si tuviera que obtener los valores al hacer la llamada al método editPersonSession.save() . Pero supongo que será suficiente. ¡Gracias! :) – Arthur

+0

No hay problema :). Siempre que se asegure de pasar los valores de los presentadores al objeto de sesión tan pronto como cambie cualquier valor en las vistas, el objeto de sesión siempre debe tener una representación actualizada de los datos en las vistas cuando llame salvar(). – Daniel

3

Si mira la página 42 del presentation de Ray Ryan de Google IO 2009, debería encontrar la solución a su pregunta. Utiliza un "bus de eventos" (instancia compartida de HandlerManager) y activa su evento PetDetailsChangedEvent personalizado y escucha ese evento desde sus widgets secundarios (página 45). Además, recuerde que mientras se desacopla, etc. es excelente y todo, algo de acoplamiento no es algo malo y podría ser una solución mejor que tratar de forzar que todo esté acoplado libremente - RR lo dice en la presentación misma :)

+0

Sí, puedo ver cómo la respuesta del servidor se puede propagar a la aplicación a través de un evento. Sin embargo, me está costando encontrar una solución para el revés, es decir, recopilar información de los diferentes widgets y luego enviar una llamada RPC "savePerson". Los únicos ejemplos que he encontrado son bastante triviales con un método getName() en la vista, por ejemplo. – Arthur

+0

Puede mantener los diferentes objetos sincronizados en el cliente con el mismo bus de eventos.Haga que cada cambio en el objeto (por ejemplo, a través de un método setter) desencadene un evento "modelChange", que todos los widgets implicados escuchan. Luego actualizan el objeto. Cuando tiene que enviar una llamada "savePerson", todos están sincronizados. – Bluu

+1

Estoy de acuerdo con el comentario de Bluu. Sin embargo, dependiendo de la aplicación, es posible que desee cambiar un poco su enfoque: primero puede guardar los datos nuevos en el servidor y luego emitir un tipo de evento "modelo modificado" (por ejemplo, con la ayuda de comed, apep). servidor o el módulo de inserción para nginx). Lo que obtendrías es que si tienes varias instancias de la aplicación abiertas en diferentes pestañas en el navegador, todas se sincronizan (es útil para cosas como clientes de chat, correo, etc., todo depende de cómo usen tus usuarios tu aplicación) . –

0

También he llegado a la conclusión de que puedo tener un modelo que corresponda a cada presentador. Entonces, un PetWidget puede crear una instancia de Pet y un PersonWidget puede crear una instancia de Persona. El PersonWidget puede contener uno o más PetWidgets, lo que a su vez significa que la clase Person puede tener una lista de instancias Pet.