He usado MVP y MVC en el pasado, y prefiero MVP ya que controla el flujo de ejecución mucho mejor en mi opinión.
He creado mi infraestructura (clases de almacén de datos / repositorio) y las uso sin problemas al codificar datos de muestra, por lo que ahora me estoy moviendo a la GUI y preparando mi MVP.
Sección a
He visto a MVP usar la vista como punto de entrada, es decir, en el método del constructor de vistas crea el presentador, que a su vez crea el modelo, conectando los eventos según sea necesario.
También he visto al presentador como el punto de entrada, donde se crean una vista, modelo y presentador, a este presentador se le da una vista y un objeto modelo en su constructor para conectar los eventos.
Como en 2, pero el modelo no se pasa al presentador. En cambio, el modelo es una clase estática donde se llaman métodos y se devuelven respuestas directamente.
Sección B
En términos de mantener la vista y el modelo sincronizados que he visto.
Siempre que cambie un valor en la vista, es decir,
TextChanged
evento en .Net / C #. Esto activa un elementoDataChangedEvent
que se pasa al modelo para mantenerlo sincronizado en todo momento. Y cuando el modelo cambia, es decir, un evento de fondo que escucha, la vista se actualiza mediante la misma idea de generar unDataChangedEvent
. Cuando un usuario desea confirmar los cambios,SaveEvent
se activa y pasa al modelo para guardarlos. En este caso, el modelo imita los datos de la vista y procesa acciones.Similar a # b1, sin embargo, la vista no se sincroniza con el modelo todo el tiempo. En cambio, cuando el usuario quiere confirmar los cambios,
SaveEvent
es despedido y el presentador toma los últimos detalles y los pasa al modelo. en este caso, el modelo no conoce los datos de las vistas hasta que se requiere que actúe sobre ellos, en cuyo caso se pasan todos los detalles necesarios.
Sección C
Visualización de objetos comerciales en la vista, es decir, un objeto (MyClass) no datos primitivos (int, double)
La vista tiene campos de propiedad para todos sus datos que se mostrarán como objetos de dominio / negocios. Tal como
view.Animals
expone unaIEnumerable<IAnimal>
propiedad, aunque la vista los procese en Nodos en un TreeView. Luego para el animal seleccionado se expondríaSelectedAnimal
comoIAnimal
propiedad.La vista no tiene conocimiento de los objetos de dominio, expone la propiedad solo para los tipos de objetos incluidos primitivo / framework (.Net / Java). En este caso, el presentador pasará un objeto adaptador al objeto de dominio, luego el adaptador traducirá un objeto comercial dado a los controles visibles en la vista. En este caso, el adaptador debe tener acceso a los controles reales en la vista, no cualquier vista, por lo que se acopla más estrechamente.
Sección D
Múltiples vistas utilizadas para crear un solo control. es decir, tiene una vista compleja con un modelo simple como guardar objetos de diferentes tipos. Puede tener un sistema de menús a un lado con cada clic en un elemento que muestra los controles apropiados.
Crea una vista enorme, que contiene todos los controles individuales que se exponen a través de la interfaz de vistas.
Tienes varias vistas. Tiene una vista para el menú y un panel en blanco. Esta vista crea las otras vistas requeridas pero no las muestra (visible = false), esta vista también implementa la interfaz para cada vista que contiene (es decir, vistas secundarias) para que pueda exponerse a un presentador. El panel en blanco se llena con otras vistas (
Controls.Add(myview)
) y ((myview.visible = true
). Los eventos generados en estas vistas "secundarias" son manejados por la vista principal, que a su vez pasa el evento al presentador, y viceversa para proporcionar eventos a elementos secundarios.Cada vista, ya sea la vista principal principal o secundaria, está conectada a su propio presentador y modelo. Literalmente, puede soltar un control de vista en un formulario existente y tendrá la funcionalidad lista, solo necesita conectarse a un presentador detrás de escena.
Sección E
Si todo tiene una interfaz, ahora, según la forma en que se haga el MVP en los ejemplos anteriores, afectará esta respuesta, ya que podrían no ser compatibles.
Todo tiene una interfaz, la vista, el presentador y el modelo. Cada uno de estos obviamente tiene una implementación concreta. Incluso si solo tiene una vista concreta, modelo y presentador.
La Vista y el Modelo tienen una interfaz. Esto permite que las vistas y los modelos difieran. El presentador crea / recibe objetos de vista y modelo y solo sirve para pasar mensajes entre ellos.
Solo la Vista tiene una interfaz. El modelo tiene métodos estáticos y no se crea, por lo que no se necesita una interfaz. Si desea un modelo diferente, el presentador llama a un conjunto diferente de métodos de clase estática. Siendo estático, el modelo no tiene ningún enlace con el presentador.
Pensamientos personales
De todas las diferentes variaciones que he presentado (la mayoría probablemente las he usado de alguna forma) de las cuales estoy seguro de que hay más. Prefiero A3 porque mantiene la lógica de negocios reutilizable fuera de solo MVP, B2 para menos duplicación de datos y menos eventos que se disparan. C1 por no agregar en otra clase, seguro que pone una pequeña cantidad de lógica no comprobable en la unidad en una vista (cómo se visualiza un objeto de dominio) pero esto podría revisarse en código o simplemente verse en la aplicación. Si la lógica fuera compleja, estaría de acuerdo con una clase de adaptador, pero no en todos los casos. Para la sección D, creo que D1 crea una vista que es demasiado grande al menos para un ejemplo de menú. He usado D2 y D3 antes. El problema con D2 es que tiene que escribir mucho código para enrutar eventos hacia y desde el presentador a la vista secundaria correcta, y no es compatible con arrastrar / soltar, cada nuevo control necesita más cableado para admitir el único presentador. D3 es mi opción preferida, pero agrega aún más clases como presentadores y modelos para lidiar con la vista, incluso si la vista es muy simple o no necesita ser reutilizada. Creo que una combinación de D2 y D3 se basa mejor en las circunstancias. En cuanto a la sección E, creo que todo lo que tiene una interfaz podría ser excesivo. Ya lo hago para objetos de dominio / negocios y, a menudo, no veo ninguna ventaja en el "diseño" al hacerlo, pero ayuda a burlarse de los objetos en las pruebas. Personalmente, vería E2 como una solución clásica, aunque he visto E3 utilizado en 2 proyectos en los que he trabajado anteriormente. Creo que una combinación de D2 y D3 se basa mejor en las circunstancias. En cuanto a la sección E, creo que todo lo que tiene una interfaz podría ser excesivo. Ya lo hago para objetos de dominio / negocios y, a menudo, no veo ninguna ventaja en el "diseño" al hacerlo, pero ayuda a burlarse de los objetos en las pruebas. Personalmente, vería E2 como una solución clásica, aunque he visto E3 utilizado en 2 proyectos en los que he trabajado anteriormente. Creo que una combinación de D2 y D3 se basa mejor en las circunstancias. En cuanto a la sección E, creo que todo lo que tiene una interfaz podría ser excesivo. Ya lo hago para objetos de dominio / negocios y, a menudo, no veo ninguna ventaja en el "diseño" al hacerlo, pero ayuda a burlarse de los objetos en las pruebas. Personalmente, vería E2 como una solución clásica, aunque he visto E3 utilizado en 2 proyectos en los que he trabajado anteriormente.
Pregunta
¿Estoy implementando MVP correctamente? ¿Hay una manera correcta de hacerlo?
Leí el trabajo de Martin Fowler que tiene variaciones, y recuerdo que cuando comencé a hacer MVC, entendí el concepto, pero originalmente no pude averiguar dónde está el punto de entrada, todo tiene su propia función, pero controla y crea el original. conjunto de objetos MVC.
fuente
Respuestas:
Mucho de lo que presentas aquí es muy razonable y sólido. Algunas de las opciones dependerán de detalles específicos de la aplicación y cuál "se siente" bien. Como es el caso la mayoría de las veces, no habrá una respuesta correcta. Algunas de las opciones tendrán sentido aquí y esas opciones podrían estar completamente equivocadas para la próxima aplicación y circunstancias. Sin conocer algunos de los detalles de la aplicación, creo que está en el camino correcto y ha tomado algunas decisiones sensatas y reflexivas.
Para mí, siento que el presentador casi siempre debería ser el punto de entrada. Tener la IU como punto de entrada pone demasiada lógica en la IU y le quita la capacidad de sustituir una nueva IU sin grandes cambios de codificación. Y realmente ese ES EL trabajo del presentador.
fuente
Utilizamos una forma modificada de MVP en nuestra aplicación .NET 2.0 Winforms. Las dos piezas que nos faltaban eran un adaptador modificado del WPF ViewModel y agregar enlace de datos. Nuestro patrón específico es MVPVM.
Nos conectamos como presentadores primero en casi todos los casos, excepto en los controles de usuario personalizados, que están conectados en vista primero para facilitar el diseño. Utilizamos inyección de dependencia, ViewModels generados por código, BDD para los presentadores y TDD / TED para el modelo.
Las máquinas virtuales son solo una gran cantidad de propiedades planas que aumentan PropertyChanged cuando se cambian. Fue muy fácil generarlos por código (y sus pruebas de unidad de ejercicio asociadas). Los usamos para leer y escribir en controles interactivos con el usuario y para controlar estados habilitados. El modelo de vista se combina con la vista, ya que utilizamos el enlace de datos para casi todo lo demás.
La Vista ocasionalmente tendrá métodos para lograr cosas que la VM no puede. Esto generalmente controla la visibilidad de los elementos (WinForms puede ser exigente al respecto) y las cosas que se niegan a estar vinculadas a los datos. La Vista siempre expone eventos como "Iniciar sesión" o "Reiniciar", con EventArgs apropiados para actuar sobre los comportamientos del usuario. A menos que hayamos tenido que usar un truco como "View.ShowLoginBox", la Vista es completamente intercambiable siempre que cumpla con los requisitos generales de diseño.
Nos tomó unos 6-8 meses para concretar este patrón. Tiene muchas piezas, pero es muy flexible y extremadamente potente. Nuestra implementación específica es muy asíncrona e impulsada por eventos, lo que puede ser un artefacto de otros requisitos en lugar de un efecto secundario del comportamiento del diseño. Por ejemplo, agregué sincronización de subprocesos a la clase base de la que heredan nuestras máquinas virtuales (que simplemente expuso un método OnPropertyChanged para generar el evento), y ahora, podemos tener presentadores y modelos multiproceso.
fuente
Estoy usando una versión de PureMvc que ha sido modificada para .Net y luego la extendí yo mismo.
Estaba acostumbrado a PureMvc de usarlo en aplicaciones Flex. Es un tipo de estructura básica, por lo que es bastante fácil de adaptar si desea personalizarlo.
Me tomé las siguientes libertades:
En PureMvc, puede usar un comando como punto de entrada, un comando de inicio típico configuraría el modelo en la medida de lo posible, luego crearía el formulario principal, crearía y registraría el mediador para y con ese formulario, y luego haría Application.Run en forma.
El mediador para el formulario sería responsable de configurar todos los sub-mediadores, algo de esto puede automatizarse, nuevamente, utilizando trucos de reflexión.
El sistema que estoy usando es compatible con arrastrar / soltar, si entiendo su significado. El formulario real se creó en VS, pero mi experiencia es solo con formularios que tienen controles creados estáticamente. Cosas como elementos de menú creados dinámicamente parecen factibles con algunos ajustes del mediador para ese menú o submenú. Donde se pondría difícil es cuando el mediador no tenía un elemento raíz estático para engancharse y usted se metió en la creación de mediadores dinámicos de 'instancia'.
fuente