Estoy tratando de comprender bien cómo implementar un buen desacoplamiento entre una interfaz de usuario y el modelo, pero tengo problemas para determinar exactamente dónde dividir las líneas.
He estado mirando Model-View-Presenter, pero no estoy seguro de cómo proceder para implementarlo. Por ejemplo, mi Vista tiene múltiples cuadros de diálogo.
- ¿Debería haber una clase View con instancias de cada uno de los cuadros de diálogo? Entonces, en ese caso, ¿cómo deberían interactuar los diálogos con el presentador? es decir. Si un diálogo individual necesita solicitar datos del Modelo a través del Presentador, ¿cómo debería el diálogo obtener una referencia al Presentador? ¿A través de una referencia a la Vista que se le dio durante la construcción?
- Estaba pensando que tal vez la vista debería ser una clase estática? Luego, los cuadros de diálogo GetView y obtener el presentador desde allí ...
- Había estado pensando en configurar el presentador con la propiedad de la vista y el modelo (en lugar de que la vista tenga el presentador y el presentador que tenga el modelo) y que el presentador registre devoluciones de llamada para eventos en la vista, pero eso parece mucho más acoplado (o el idioma dependía, al menos).
Estoy tratando de:
- hacer esto lo más desacoplado posible
- idealmente, es posible acoplar el presentador / modelo con vistas de otros idiomas (no he hecho un montón de cosas entre idiomas, pero sé que es posible, particularmente cuanto más
void(void)
puedo seguir, al menos una aplicación C # con un Biblioteca C ++ ... - mantenga el código limpio y simple
Entonces ... ¿alguna sugerencia sobre cómo deben manejarse las interacciones?
design-patterns
ui
interfaces
trata de atraparlo
fuente
fuente
Respuestas:
Bienvenido a una pendiente resbaladiza. En este punto, se ha dado cuenta de que hay una variación interminable de todas las interacciones modelo-vista. MVC, MVP (Taligent, Dolphin, Passive View), MVVM solo por nombrar algunos.
El patrón Model View Presenter, como la mayoría de los patrones arquitectónicos, está abierto a mucha variedad y experimentación. Lo único que todas las variaciones tienen en común es el papel del presentador como "intermediario" entre la vista y el modelo. Los dos más comunes son la Vista pasiva y el Presentador / Controlador supervisor - [ Fowler ]. La Vista pasiva trata la IU como una interfaz muy superficial entre el usuario y el presentador. Contiene muy poca o ninguna lógica, delegando tanta responsabilidad a un presentador. Presentador / controlador supervisorintenta aprovechar el enlace de datos integrado en muchos marcos de IU. La interfaz de usuario maneja la sincronización de datos, pero el presentador / controlador interviene para obtener una lógica más compleja. En cualquier caso, el modelo, la vista y el presentador forman una tríada
Hay muchas maneras de hacer esto. Es muy común ver esto manejado tratando cada diálogo / formulario como una vista diferente. Muchas veces hay una relación 1: 1 entre puntos de vista y presentadores. Esta no es una regla difícil y rápida. Es bastante común que un presentador maneje múltiples vistas relacionadas o viceversa. Todo depende de la complejidad de la vista y la complejidad de la lógica empresarial.
En cuanto a cómo las opiniones y los presentadores obtienen una referencia mutua, esto a veces se llama cableado . Tienes tres opciones:
La vista contiene una referencia al presentador
Un formulario o cuadro de diálogo implementa una vista. El formulario tiene controladores de eventos que delegan a un presentador mediante llamadas de función directas:
Como el presentador no tiene una referencia a la vista, la vista debe enviarle datos como argumentos. El presentador puede comunicarse con la vista utilizando eventos / funciones de devolución de llamada que la vista debe escuchar.
El presentador tiene una referencia para ver
En el escenario, la vista expone las propiedades de los datos que muestra al usuario. El presentador escucha los eventos y manipula las propiedades en la vista:
Ambos tienen una referencia entre sí formando una dependencia circular.
En realidad, este escenario es más fácil de trabajar que los demás. La vista responde a eventos llamando a métodos en el presentador. El presentador lee / modifica los datos de la vista a través de las propiedades expuestas.
Hay otros problemas a considerar con los patrones MVP. Orden de creación, vida útil del objeto, donde se realiza el cableado, comunicación entre las tríadas MVP, pero esta respuesta ya ha crecido lo suficiente.
fuente
Como todos han dicho, hay docenas de opiniones y ninguna de ellas es correcta o incorrecta. Sin entrar en la miríada de patrones y solo centrarnos en MVP, aquí hay algunas sugerencias sobre la implementación.
Mantenlos separados. La vista debe implementar una interfaz que forme el vínculo entre la vista y el presentador. La vista crea un presentador, se inyecta en el presentador y expone los métodos que ofrece para que el presentador interactúe con la vista. La vista es responsable de implementar estos métodos o propiedades de la forma que desee. Generalmente tiene una vista: un presentador, pero en algunos casos puede tener muchas vistas: un presentador (web, wpf, etc.). La clave aquí es que el presentador no sabe nada de las implementaciones de la interfaz de usuario y solo interactúa con la vista a través de la interfaz.
Aquí hay un ejemplo. Primero tenemos una clase de vista con un método simple para mostrar un mensaje al usuario:
Ahora aquí está el presentador. Tenga en cuenta que el presentador toma una IView en su constructor.
Ahora aquí está la interfaz de usuario real. Esto podría ser una ventana, un diálogo, una página web, etc. No importa. Tenga en cuenta que el constructor de la vista creará el presentador al inyectarse en él.
Al presentador no le importa cómo la vista implementa el método que simplemente hace. Por lo que sabe el presentador, podría estar escribiendo en un archivo de registro y ni siquiera mostrándolo al usuario.
En cualquier caso, el presentador trabaja un poco con el modelo en el back-end y en algún momento quiere informar al usuario sobre lo que está sucediendo. Entonces, ahora tenemos un método en algún lugar del presentador que llama a las vistas del mensaje InformUser.
Aquí es donde obtienes tu desacoplamiento. El presentador solo tiene una referencia a una implementación de IView y realmente no le importa cómo se implementa.
Esta también es una implementación deficiente del hombre, ya que tiene una referencia al Presentador en la vista y los objetos se configuran a través de constructores. En una solución más robusta, es probable que desee ver contenedores de inversión de control (IoC) como Windsor, Ninject, etc., que resolverían la implementación de IView para usted en tiempo de ejecución a pedido y, por lo tanto, lo desacoplarían aún más.
fuente
Creo que es importante recordar que el controlador / presentador es donde realmente tiene lugar la acción. El acoplamiento en el controlador es inevitable debido a la necesidad.
El punto central del Controlador es que si realiza un cambio en la Vista, el Modelo no tiene que cambiar y viceversa (si el Modelo cambia, la Vista tampoco tiene que hacerlo) porque el Controlador es lo que traduce Modelar en la vista y volver de nuevo. Pero el Controlador cambiará cuando los cambios en el Modelo o en la Vista lo hagan porque efectivamente tiene que traducir dentro del Controlador cómo se va a ver el Modelo y cómo volver a realizar los cambios en la Vista en el Modo.
El mejor ejemplo que puedo dar es que cuando escribo una aplicación MVC, no solo puedo tener datos en la vista de la GUI, sino que también puedo escribir una rutina que empuja los datos extraídos del Modelo
string
a mostrar en el depurador (y por extensión en un archivo de texto sin formato). Si puedo tomar datos del Modelo y traducirlos libremente en texto sin cambiar la Vista o el Modelo y solo el Controlador, entonces estoy en el camino correcto.Dicho esto, tendrá que tener referencias entre los diferentes componentes para que todo funcione. El Controlador necesita saber acerca de la Vista para enviar datos, la Vista necesita saber sobre el Controlador para decirle cuándo se ha realizado un cambio (como cuando el Usuario hace clic en "Guardar" o "Nuevo ..."). El controlador necesita saber sobre el modelo para extraer los datos, pero yo diría que el modelo no debería saber nada más.
Advertencia: vengo de un fondo totalmente Mac, Objective-C, Cocoa que realmente te empuja al paradigma MVC, lo quieras o no.
fuente
En general, desea que su modelo encapsule todas las interacciones con ese modelo. Por ejemplo, sus acciones CRUD (Crear, Leer, Actualizar, Eliminar) son parte del modelo. Lo mismo vale para cálculos especiales. Hay un par de buenas razones para esto:
En su controlador (aplicación MVC), todo lo que está haciendo es recopilar los modelos que necesita usar en su vista y llamar a las funciones apropiadas en el modelo. Cualquier cambio en el estado del modelo ocurre en esta capa.
Su vista simplemente muestra los modelos que preparó. Esencialmente, la vista solo lee el modelo y ajusta su salida en consecuencia.
Mapeando el principio general a clases reales
Recuerda que tus cuadros de diálogo son vistas. Si ya tiene una clase de diálogo, no hay razón para crear otra clase "Ver". La capa Presentador esencialmente vincula el modelo a los controles en la Vista. La lógica empresarial y todos los datos importantes se almacenan en el modelo.
fuente