Comprender el patrón MVC


Estoy teniendo algunos problemas para entender el patrón MVC. Entiendo que estamos tratando de desacoplar la interfaz gráfica de usuario de la lógica de negocio, aunque estoy teniendo problemas para entender cómo.

Por lo que entendí, el View, es lo que el usuario ve. Así que generalmente es la ventana / formulario. El Controller está entre el View y el Model. El Controlador hará que los datos "fluyan" en ambas direcciones. También persistirá el estado cuando sea necesario (si tengo un asistente con 5 pasos, es el Controller ' s responsabilidad de asegurarse de que se hacen en el orden correcto, etc.). El Model, es donde vive el núcleo de la lógica de mi aplicación.

¿Es este punto de vista correcto?

Para tratar de convertir esto en algo más significativo, intentaré esbozar un ejemplo simple con WinForms (no ASP.NET o WPF, por favor! - para la multitud de Java, por lo que he llegado a entender, Swing funciona de una manera similar a WinForms!), para ver si lo hago bien, y voy a plantear las preguntas que siempre vienen a hacer se.


Supongamos que tengo un modelo que contiene solo una clase (solo para hacerlo más fácil. Sé que hará que el ejemplo parezca tonto, pero es más fácil de esta manera):

class MyNumbers {
    private IList<int> listOfNumbers = new List<int> { 1, 3, 5, 7, 9 };

    public IList<int> GetNumbers() {
        return new ReadOnlyCollection<int>(listOfNumbers);
    }
}

Ahora es el momento de hacer mi Controller:

class Controller
{
    private MyNumbers myNumbers = new MyNumbers();

    public IList<int> GetNumbers() {
        return myNumbers.GetNumbers();
    }
}

El View solo debe tener un ListBox que tenga como elementos todos los números recuperados en MyNumbers.

Ahora, surge la primera pregunta:{[52]]}

¿Debería el Controller ser responsable de crear MyNumbers? En este simple caso, creo que es aceptable (como MyNumbers hará exactamente lo mismo, pase lo que pase, y no tiene estado asociado). Pero vamos a suponer que me gustaría utilizar para todos los diferentes Controladores de mi aplicación tiene la misma instancia de MyNumbers. Tendría que pasar a este Controller (y a todos los demás que lo necesiten) esa instancia de MyNumbers que quiero usar. Quién va a ser responsable de eso? En este ejemplo de WinForms, ¿sería el View? ¿O sería esa la clase que crea el View?

Dando la vuelta a la pregunta: ¿qué es la orden de instanciación de estas 3 partes? ¿Cuál es el código que el" propietario " del MVC llamó para crearlo? ¿Debería el Controller crear ambos View y Model? ¿Debería el View instanciar el Controller y el Controller el Model?

Segunda pregunta:

¿Cómo se supone que se verá el método main, asumiendo que solo quiero que mi aplicación tenga el Use Case que retrata Controller?

Tercero:

¿Por qué en el siguiente diagrama MVC, el View tiene una flecha a la Model? No debería el Controller ser siempre el puente entre ambos View y Model?

texto alt


Tendré una o dos preguntas más, pero probablemente tendrán más sentido cuando entienda este primer detalle. O tal vez después de entender esa primera pregunta todos los demás se rompen.

Gracias!

Author: Community, 2010-07-22

10 answers

La forma más fácil de obtener un control sobre MVC es usarlo en un marco que lo haga cumplir, dicho esto..

  • El Modelo interactúa con la fuente de datos (DB o lo que sea) y le da acceso a sus datos.
  • La vista interactúa con el mundo exterior, recibe entrada de algún lugar y entrega los datos al Controlador también escucha al Controlador para asegurarse de que muestra los datos correctos.
  • El Controlador es donde ocurre toda la magia; el Controlador manipula datos, envía eventos y maneja cambios en ambas direcciones (hacia/desde la Vista y hacia/desde el Modelo).

Este diagrama es muy útil (tiene mucho más sentido que el de Wikipedia): Diagrama MVC http://java.sun.com/developer/technicalArticles/javase/mvc/images/Figure4.gif

Fuente, y un gran artículo sobre MVC!

 25
Author: xj9,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-22 14:33:32

En cuanto a la crítica dentro de mi post pensé que daría un post sobre cómo tiendo a crear un patrón MVC en PHP

Dentro de PHP escupo el framework en varias secciones, de las cuales algunas son las normales cuando se trata de MVC.

Primarias:

  • Controlador
  • Modelo
  • Ver

Secondariness - ModelLayer

  • ViewLoader
  • Biblioteca
  • ErrorLayer

Dentro del controlador normalmente permito a todos el acceso a las capas secundarias y la Vista y el Modelo desde el Primario.

Esta es la forma en que lo estructuraría{[16]]}

|---------|       |------------|       |------------|
| Browser | ----> | Controller | ----> |   Model    |
|---------|       |------------|       |------------|
     |                  |   |                |
     |                  |   |----------------|
     |                  |
     |            |------------|
     -------------|    View    |
                  |------------|

Desde mi diagrama normalmente omito la conexión View <-> Model y hago un Controller <-> Model y luego el enlace de Controller <-> View asigna los datos.

Dentro de mi marco tiendo a crear un sistema de almacenamiento de objetos para que pueda recuperar fácilmente objetos y así sucesivamente. un ejemplo de mi almacenamiento de objetos es así

class Registry
{
   static $storage = array();

   public static function get($key)
   {
       return isset(self::storage[$key]) ? self::storage[$key] : null;
   }

   public static function set($key,$object)
   {
       self::"storage[$key] = $object;
   }
}

Algo más avanzado por ese es el esquema, por lo que con esto cuando inicializo por primera vez los objetos los almaceno como Registry::set("View",new View()); para que siempre estén accesibles.

Así que dentro de mi bruja controlador es el controlador base creo varios métodos mágicos__get() __set() para que cualquier clase que extienda el controlador pueda devolver fácilmente la petición por ejemplo:

abstract class Controller
{
   public function __get($key)
   {
       //check to make sure key is ok for item such as View,Library etc

       return Registry::get($key); //Object / Null
   }
}

Y el usuario controlador

class Controller_index extends Controller
{
    public function index()
    {
       $this->View->assign("key","value"); // Exucutes a method in the View class
    }
}

El modelo también se colocará en el registro, pero solo se podrá llamar desde ModelLayer

class Model_index extends ModelLayer_MySql
{
}

O

class Model_index extends ModelLayer_MySqli
{
}

O sistema de archivos

class Model_file extends ModelLayer_FileSystem
{
}

Para que cada clase pueda ser específica para el tipo de almacenamiento.

Este no es el tipo tradicional de Patrón MVC, pero se puede llamar MVC Adoptivo.

Otros objetos como el View Loader no deben colocarse en el registro, ya que no están específicamente para los intereses de los usuarios, sino que son utilizados por otras entidades como View

abstract class ViewLoader
{
   function __construct($file,$data) //send the file and data
   {
       //Include the file and set the data to a local variable
   }

   public function MakeUri()
   {
       return Registry::get('URITools')->CreateURIByArgs(func_get_args());
   }
}

Como el archivo de plantilla está siendo incluido en el cargador de vista y NO en la clase de vista, separa los métodos de usuario de los métodos del sistema teh y también permite que los métodos se utilicen dentro de las propias vistas para la lógica general.

Ejemplo de archivo de plantilla.

<html>
   <body>
      <?php $this->_include("another_tpl_file.php"); ?>
      <?php if(isset($this->session->admin)):?>

          <a href="<?php echo $this->MakeUri("user","admin","panel","id",$this->session->admin_uid) ?>"><?php echo $this->lang->admin->admin_link ?></a>

      <?php endif; ?>
   </body>
</html>

Espero que mis ejemplos te ayuden a entender eso un poco más.

 3
Author: RobertPitt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-22 15:43:19

Respuesta a la tercera cuestión

Cuando el modelo cambia, notifica a la vista, luego la vista obtiene los datos del modelo usando sus captadores.

 2
Author: Zoltan Balazs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-22 14:28:21

"Por lo que entendí, la Vista, es lo que ve el usuario. Así que generalmente es la ventana / formulario. El Controlador está entre la Vista y el Modelo. El Controlador "manejará" los datos en ambas direcciones. También persistirá el estado cuando sea necesario (si tengo un asistente con 5 pasos, es responsabilidad del Controlador asegurarse de que se realicen en el orden correcto, etc.). El Modelo, es donde vive el núcleo de la lógica de mi aplicación."

Esto es casi correcto. El controlador no persiste datos. Llama a un servicio que conserva datos. La razón es que la persistencia de datos nunca es solo una llamada para guardar. Es posible que desee hacer comprobaciones de validación de los datos para asegurarse de que estén sanos de acuerdo con las necesidades de su negocio. Es posible que desee realizar alguna autenticación para asegurarse de que los datos puedan ser guardados por un usuario. Si lo hace en un servicio, entonces tiene un buen paquete de funcionalidad que puede usar una y otra vez, por ejemplo, para una aplicación web y un servicio web. Si lo haces en un controlador, por ejemplo web app, cuando vayas a escribir tu servicio web tendrás que refactorizar y / o duplicar código.

En respuesta a su comentario "No estoy seguro de haber entendido totalmente su punto. ¿El Controlador comprueba la entrada de la interfaz de usuario, o es el Modelo que lo hace?"

El controlador solo debe controlar qué rutas de funcionalidad de negocio se ejecutan. Eso es. Los controladores deberían ser la parte más fácil de escribir del código. Puede hacer alguna validación en la gui (es decir, ver, por ejemplo, asegurarse de que el correo electrónico las direcciones están formateadas correctamente, las entradas de texto no exceden los máximos), pero la capa de negocio también debe validar la entrada for por la razón que mencioné anteriormente, que cuando empiezas a colocar más puntos finales, no tienes que refactorizar.

 1
Author: hvgotcodes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-22 14:18:36

En caso de que el Controlador sea responsable ¿para crear MyNumbers?

Yo diría ' definitivamente no.'

Si el patrón MVC está diseñado para desacoplar los elementos M, V, & C, ¿cómo puede funcionar esto si la C simplemente crea una instancia de la M con new MyNumbers()?

En Java, usaríamos algo como el Spring Framework aquí. Necesita una forma de expresar la relación de dependencia in o más bien los detalles de cómo se cumple in en un archivo de configuración u otro lugar adecuado ( es decir, no en el código compilado).

Pero hay otro elemento en este problema: probablemente no debería definir la variable myNumbers (dentro de C) con el tipo concreto de tiempo de ejecución que pretende usar. Utilice una interfaz o una clase abstracta, y déjelo abierto en cuanto a cuál es el tipo de tiempo de ejecución real. De esta manera, en el futuro puede volver a implementar la interfaz IMyNumbers para satisfacer los requisitos emergentes (aquellos que no conoce hoy) y su componente C continuará funciona perfectamente, nadie se da cuenta.

 1
Author: Drew Wills,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-22 14:29:13

¿Por qué en el siguiente diagrama MVC, la vista tiene una flecha hacia el Modelo? ¿No debería el Controlador ser siempre el puente entre la Vista y el Modelo?

Es el modelo MVC 2. Se puede ver por lo general en la aplicación Java enterprise donde CONTROL hace el negocio, así como procesa los datos desde / hacia el MODELO y elige qué VISTA devolver al cliente. Al renderizar al cliente, VIEW utilizará datos del MODELO:

Texto alternativo http://www.blogjava.net/images/blogjava_net/marco/7342/o_2.JPG

Aquí hay un ejemplo de cómo acceder a los datos de un archivo JSP (VISTA) que un bean (MODELO):

class Person {String name;} // MODEL
My name is ${bean.name}     // VIEW
 1
Author: Truong Ha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-22 14:45:54

Esto es de Java, pero espero que ayude.

Para el principal:

public static void main(String[] args) 
{
       MyNumbers myNums = new MyNumbers();  // Create your Model
       // Create controller, send in Model reference.      
       Controller controller = new Controller(myNums); 
}

Su controlador necesita una referencia a su modelo. En este caso, el controlador realmente crea todos los componentes Swing. Para C#, es posible que desee dejar la inicialización del formulario aquí, pero la Vista / Formulario necesita una referencia al Modelo (myNums) y al Controlador (controller). Esperemos que algunas personas de C# puedan ayudar en este frente. La vista también necesita registrarse como Observador del Modelo (ver Observador Patrón).

Aquí está el constructor que tengo (ajustado para su caso):

public NumberView(Controller controller, MyNumbers myNums)
{
      this.controller = controller; // You'll need a local variable for this
      this.myNums = myNums; //You'll need a local variable for this
      myNums.registerObserver(this); // This is where it registers itself
}

La Vista pasa el trabajo al Controlador para manejar las acciones del usuario (botones, lo que sea). El Controlador decide qué llamar / hacer en el Modelo. En general, el Modelo entonces hace algo y cambia su estado (tal vez más números en su lista. Haga lo que haga). En ese momento, el Modelo hará saber a sus Observadores que ha cambiado y que se actualicen. A continuación, la vista va y obtiene los nuevos datos y se actualiza. Es por eso que el Modelo y Ver hablar (su 3a pregunta).

Así que el Modelo tendrá:

public void notifyObservers()
{
    for (Observer o: observers)
    {
        o.update();  // this will call the View update below since it is an Observer
    }
}

Así que en la vista, tendrás algo como esto:

public void update()
{
    setListBox(myNums.getNumbers());  // Or whatever form update you want
}

Espero que eso ayude. Sé que es Java, pero el concepto todavía se aplica. Tendrás que hacer una pequeña lectura sobre el patrón del Observador para obtenerlo completamente. ¡Buena suerte!

 1
Author: Awaken,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-22 14:54:39

Trataré de responder a esto desde una posición relativamente menos técnica para lo que vale. Voy a tratar de caminar a través de un ejemplo general.

Controller controla lo que view se usa. Así, por ejemplo, si usted está escribiendo a la página el controller le dirigirá a la input view (por ejemplo) mientras que si usted está leyendo la misma página le dirigirá a su success view (por ejemplo).

Después de escribir en la página, controller pasará esos parámetros a la model relevante donde la lógica correspondiente a lo que debe hacerse con ellos reside. Si hay un error, entonces el controller te dirigirá al error view.

Mi conocimiento se basa en mi experiencia de un mes con Agavi. Espero que esto ayude.

 1
Author: Jungle Hunter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-22 15:13:31
  • La vista dibuja el modelo y lo representa para el usuario
  • El controlador maneja la entrada del usuario y las traduce a las modificaciones en el modelo
  • El modelo contiene los datos y la lógica de modificación

No tiene sentido traducirlo en código. De todos modos, no lo entenderás correctamente.

 0
Author: Cheery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-22 14:46:22

Ver

  • Interfaz de usuario / responsable con input output / alguna validación / necesita tener una manera de notificar al mundo exterior de eventos de nivel de interfaz de usuario

  • Conoce solo el modelo

Modelo

  • estructura de datos / representa los datos que se presentan/no debe contener lógica de negocio (tal vez solo algunos datos / validación de la estructura a lo sumo)
  • solo sabe de sí mismo (piense en una clase de Persona que solo tiene Nombre y Edad)

Controlador

  • Es responsable de la lógica de negocio / empaqueta vistas y pega los modelos respectivos en ellas / tiene que ser capaz de responder a eventos de vista / accede a otras capas de la aplicación (persistencia / servicios externos / capas de negocio, etc.)

  • Sabe todo (al menos Ver y modelar) y se encarga de pegarlo todo

 0
Author: Adrian Zanescu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-22 15:33:00