29 votos

La separación de las preocupaciones; MVC; ¿por qué?

Actualmente estoy leyendo en los OO antes de embarcarse en mi próximo gran proyecto. Para darle una rápida fondo, soy un desarrollador de PHP, trabajando en aplicaciones web.

Un área en la que particularmente me interesa es la Interfaz de Usuario; específicamente cómo construir este y conectarlo a mi OO "modelo".

He estado leyendo algo sobre esta área. Uno de mis favoritos es este: La construcción de interfaces de usuario para sistemas orientados a objetos

"Todos los objetos deben proporcionar su propia interfaz de usuario"

Pensando acerca de mi problema, veo que este funcionando bien. Voy a construir mi objeto "user" para representar a alguien que ha entrado en mi sitio web, por ejemplo. Uno de mis métodos, a continuación, "display_yourself" o similar. Puedo usar esto a lo largo de mi código. Quizás para empezar con esto sólo será su nombre. Más tarde, si tengo que ajustar para mostrar su nombre+pequeño avatar, solo puedo actualizar este método y hey presto, mi aplicación se actualiza. O si me necesita para hacer de su nombre un enlace a su perfil, hey presto puedo actualizar de nuevo fácilmente de un lugar.

En términos de un sistema OO; creo que este enfoque funciona bien. Buscando en otros StackOverflow hilos, he encontrado esto en virtud de la "Separación de Preocupaciones": Soc

"En ciencias de la computación, la separación de la los problemas (SoC) es el proceso de la ruptura de un programa de ordenador en distintas características que se superponen en funcionalidad como poco como sea posible. Un la preocupación es cualquier pieza de interés o se centran en un programa. Normalmente, las preocupaciones son sinónimo de características o comportamientos. El progreso hacia el SoC es tradicionalmente se logra a través de la modularidad y la encapsulación, con el ayudar a la ocultación de información."

A mi mente he conseguido. Mi objeto de usuario se esconde todo es información. Yo no tengo ningún lugares en mi código donde yo digo $usuario->get_user_name() antes de que me lo muestre.

Sin embargo, esto parece ir en contra de lo que otras personas parecen pensar como "mejor práctica".

Para citar a los "seleccionados" (verde) responder de la misma pregunta:

"La separación de las preocupaciones es la de mantener la el código para cada una de estas preocupaciones separado. El cambio de la interfaz no debe requerir el cambio de la la lógica de negocio de código, y viceversa. Modelo-Vista-Controlador (MVC) el diseño de el patrón es un excelente ejemplo de la separación de estas preocupaciones para mejor software de mantenimiento."

¿Por qué este hacer para el mejor software de mantenimiento? Seguramente con MVC, mi punto de Vista tiene que saber un montón sobre el Modelo? Leer el JavaWorld artículo para una discusión detallada sobre este punto: La construcción de interfaces de usuario para sistemas orientados a objetos

De todos modos... llegar al punto real, ¡por fin!

1. ¿Alguien puede recomendar algunos libros que discutir esto en detalle? No quiero un MVC libro; no estoy vendido en MVC. Quiero un libro que analiza OO / interfaz de usuario, los problemas potenciales, las posibles solutuions etc.. (tal vez incluyendo MVC) Arthur Riel del Diseño Orientado a Objetos Heurística

toca en ella (y es un excelente libro!), pero quiero algo que entra en más detalle.

2. Cualquiera puede proponer un argumento que es así-explicó como Allen Holub del JavaWorld artículo que explica por qué MVC es una buena idea?

Muchas gracias para quien me puede ayudar a llegar a una conclusión sobre este.

29voto

Boden Puntos 2242

Esta es una falla en la forma en la programación orientada a objetos es que a menudo se enseña, el uso de ejemplos como el rectángulo.draw() y de los dinosaurios.show() que no tienen ningún sentido.

Casi está respondiendo a su propia pregunta cuando hablas de tener una clase de usuario que muestra a sí mismo.

"Más adelante, si tengo que ajustar para mostrar su nombre+pequeño avatar, solo puedo actualizar este método y hey presto, mi aplicación se actualiza."

Pensar en esa pequeña pieza para el momento. Ahora echa un vistazo a Stack Overflow y notificación de todos los lugares en los que su nombre de usuario aparece. Qué aspecto de la misma en cada caso? No, en la parte superior tienes un sobre junto a su nombre de usuario seguido por su reputación y distintivos. En una conversación de preguntas que tienes tu avatar, seguido por el nombre de usuario con su reputación e insignias debajo de ella. ¿Crees que es un objeto de usuario con métodos como getUserNameWithAvatarInFrontOfItandreputationandbadgesunderneath() ? Nah.

Un objeto es que se trate con los datos a los que representa y los métodos que actúan sobre los datos. Su objeto de usuario probablemente tendrá nombre y apellidos de los miembros, y la necesaria getters para recuperar esas piezas. También podría haber una comodidad como método toString ()) (en Java) que devuelve el nombre del usuario en un formato común, como el primer nombre seguido de un espacio y luego el apellido. Aparte de eso, el objeto de usuario no debe hacer mucho más. Es hasta el cliente para decidir lo que quiere hacer con el objeto.

Tomemos el ejemplo que nos has dado con el objeto de usuario y, a continuación, pensar en cómo se podría hacer lo siguiente, si usted construye una "interfaz de usuario" en él:

  1. Crear un CSV de exportación mostrando todos los usuarios, ordenados por apellido. E. g. Apellido, Nombre.
  2. Un peso pesado de la interfaz gráfica de usuario y una interfaz basada en Web para trabajar con el objeto de usuario.
  3. Mostrar un avatar al lado del nombre de usuario en un solo lugar, pero sólo se mostrará el nombre de usuario en otro.
  4. Proporcionar una lista de RSS los usuarios.
  5. Mostrar el nombre de usuario en negrita en un solo lugar, en cursiva en el otro, y como un hipervínculo en otro lugar.
  6. Mostrar al usuario la inicial del medio donde corresponda.

Si usted piensa acerca de estos requisitos, todos ellos se reducen a la prestación de un objeto de usuario que se preocupa sólo de los datos que deben estar preocupados. No debe tratar de ser todo para todo el mundo, sólo debe proporcionar un medio para llegar a los datos del usuario. Corresponde a cada uno de los muchos puntos de vista que se va a crear para decidir cómo desea mostrar los datos de usuario.

Su idea acerca de la actualización del código en un lugar a la actualización de sus puntos de vista en muchos lugares es una buena. Esto es todavía posible sin ensuciar con las cosas a un nivel demasiado bajo. Ciertamente se podría crear widget-como las clases que encapsulan sus diferentes puntos de vista comunes de "cosas", y el uso de ellos en todo el código de la vista.

21voto

GloryFish Puntos 3388

Aquí es el enfoque que toma a la hora de crear sitios web en PHP usando MVC/separación de preocupaciones patrón:

El marco que yo uso tiene tres partes básicas:

  • Los modelos de Clases PHP. Puedo añadir métodos a ellos para extraer y guardar los datos. Cada el modelo representa un tipo distinto de la entidad en el sistema: usuarios, páginas, entradas de blog
  • Puntos de vista - plantillas Smarty. Aquí es donde el código html vidas.
  • Controladores - clases PHP. Estos son los cerebros de la aplicación. Normalmente url del sitio invocar los métodos de la clase. example.com/user/show/1 sería invocar el $user_controller->mostrar(1) método. El controlador obtiene los datos de salida de la modelo y le da a la vista.

Cada una de estas piezas tiene un trabajo específico o "preocupación". El modelo's trabajo es proporcionar una interfaz limpia a los datos. Normalmente el sitio de datos se almacena en una base de datos SQL. Puedo añadir métodos para el modelo para la obtención de datos y almacenamiento de datos.

La vista's trabajo es mostrar los datos. Todas las etiquetas HTML que va en la vista. La lógica para controlar cebra-la creación de bandas para una tabla de datos va en la vista. Código para controlar el formato de una fecha que se debe mostrar en va en la vista. Me gusta el uso de plantillas Smarty para las vistas ya que ofrece algunas características interesantes para manejar las cosas como esa.

El controlador's trabajo es actuar como intermediario entre el usuario, el modelo y la vista.

Veamos un ejemplo de cómo estos vienen juntos y donde los beneficios se encuentran:

Imagina un simple sitio de blog. La pieza principal de datos es un post. Además, imagino que el sitio mantiene un seguimiento del número de veces que un post se ve. Vamos a crear una tabla de SQL para que:

posts
id date_created title body hits

Ahora supongamos que desea mostrar los 5 posts más populares. He aquí lo que se puede ver en la no aplicación de MVC:

$sql = "SELECT * FROM posts ORDER BY hits DESC LIMIT 5";
$result = mysql_query($sql);

while ($row = mysql_fetch_assoc($result)) {
    echo "<a href="post.php?id=$row['id']">$row['title']</a><br />";
}

Este fragmento de código es bastante sencillo y funciona bien si:

  1. Es el único lugar en el que desea mostrar los posts más populares
  2. Usted nunca desea cambiar cómo se ve
  3. Nunca se decide a cambiar lo que es un "post" es

Imaginemos que queremos mostrar los 10 posts más populares en la página de inicio y los 5 más populares en una barra lateral en las subpáginas. Ahora necesita duplicar el código de arriba, o ponerlo en un archivo de inclusión con la lógica para comprobar dónde se muestran.

Lo que si desea actualizar el marcado de la página de inicio para agregar un "nuevo post" de la clase de puestos que se han creado hoy en día?

Supongamos que usted decide que un post es muy popular debido a que tiene un montón de comentarios, no se golpea. La base de datos va a cambiar para reflejar esto. Ahora, cada lugar, en su aplicación que muestra las entradas populares debe ser actualizado para reflejar la nueva lógica.

Usted está comenzando a ver una bola de nieve de la complejidad de la forma. Es fácil ver cómo las cosas pueden llegar a ser cada vez más difícil de mantener en el curso de un proyecto. También, considere la complejidad cuando varios desarrolladores están trabajando en un proyecto. Si el diseñador tiene que consultar con el desarrollador de base de datos al agregar una clase a la salida?

Tomando un enfoque MVC y ejecución de una separación de preocupaciones dentro de la aplicación puede mitigar estos problemas. Idealmente, nos quieren separar a cabo en tres áreas:

  1. datos de la lógica de
  2. la lógica de la aplicación
  3. y la lógica de presentación

Vamos a ver cómo hacer esto:

Comenzaremos con el modelo. Vamos a tener un $post_model de la clase y darle un método llamado get_popular(). Este método devuelve un array de mensajes. Además vamos a darle un parámetro para especificar el número de puestos de volver:

post_model.php

class post_model {
    public function get_popular($number) {
        $sql = "SELECT * FROM posts ORDER BY hits DESC LIMIT $number";
        $result = mysql_query($sql);
        while($row = mysql_fetch_assoc($result)) {
            $array[] = $row;
        }
        return $array;
    } 
}

Ahora la página de inicio tenemos un controlador, vamos a llamar "hogar". Imaginemos que tenemos una url esquema de enrutamiento que invoca nuestro controlador cuando la página de inicio que se solicita. Su trabajo es conseguir entradas populares y darles el punto de vista correcto:

home_controller.php

class home_controller {
    $post_model = new post_model();
    $popular_posts = $post_model->get_popular(10);

    // This is the smarty syntax for assigning data and displaying
    // a template. The important concept is that we are handing over the 
    // array of popular posts to a template file which will use them 
    // to generate an html page
    $smarty->assign('posts', $popular_posts);
    $smarty->view('homepage.tpl');
}

Ahora vamos a ver lo que la vista se vería así:

homepage.tpl   

{include file="header.tpl"}

 // This loops through the posts we assigned in the controller
 {foreach from='posts' item='post'} 
    <a href="post.php?id={$post.id}">{$post.title}</a>
 {/foreach}

{include file="footer.tpl"}

Ahora tenemos las piezas básicas de nuestra aplicación y se puede ver la separación de preocupaciones.

El modelo se preocupa de la obtención de los datos. Se sabe acerca de la base de datos, se sabe acerca de consultas SQL y LÍMITE de declaraciones. Sabe que debe de mano con una buena selección.

El controlador sabe acerca de la petición del usuario, que está mirando la página de inicio. Se sabe que el sitio web debe mostrar los 10 puestos popular. Se obtiene los datos del modelo y se la da a la vista.

La vista sabe que hay una serie de puestos debe visualizarse como una serie de acor etiquetas con las etiquetas de salto después de ellos. Se sabe que un post tiene un título y una identificación. Se sabe que el título de un post debe ser utilizado para el texto de anclaje y que los puestos id debe ser utilizado en el href. La vista también sabe que no debe ser un encabezado y pie de página se muestra en la página.

También es importante mencionar lo que cada pieza no saber.

La modelo no sabe que las entradas populares se muestran en la página de inicio.

El controlador y la vista no saben que los mensajes se almacenan en una base de datos SQL.

El controlador y el modelo de no saber que cada enlace a un post en la página de inicio debe tener una etiqueta de salto después de ella.

Así, en este estado hemos establecido una clara separación de las preocupaciones entre los datos de la lógica (el modelo), la lógica de la aplicación (en el controlador), y la lógica de presentación (la vista). ¿Y ahora qué? Tomamos un simple fragmento de código PHP y se rompió en tres confuso archivos. ¿Esto qué nos dan?

Echemos un vistazo a cómo tener una separación de preocupaciones nos puede ayudar con los problemas mencionados anteriormente. Para reiterar, queremos:

  1. Mostrar las entradas populares en una barra lateral en las subpáginas
  2. Destacan los nuevos posts con una clase css
  3. Cambiar la definición subyacente de un "post"

Para mostrar el popular puestos en una barra lateral que vamos a añadir dos archivos de nuestro subpágina:

Una subpágina el controlador...

subpage_controller.php

class subpage_controller {
    $post_model = new post_model();
    $popular_posts = $post_model->get_popular(5);

    $smarty->assign('posts', $popular_posts);
    $smarty->view('subpage.tpl');
}

...y una subpágina de la plantilla:

subpage.tpl

{include file="header.tpl"}

<div id="sidebar">

 {foreach from='posts' item='post'}
    <a href="post.php?id={$post.id}">{$post.title}</a>
 {/foreach}

</div>

{include file="footer.tpl"}

La nueva subpágina controlador sabe que la subpágina debe mostrar sólo 5 entradas populares. La subpágina de vista sabe que subpáginas debe poner la lista de los puestos dentro de un div de la barra lateral.

Ahora, en la página de inicio queremos destacar los nuevos puestos. Podemos lograr esto mediante la modificación de la página de inicio.tpl.

{include file="header.tpl"}

 {foreach from='posts' item='post'}
    {if $post.date_created == $smarty.now}
        <a class="new-post" href="post.php?id={$post.id}">{$post.title}</a>
    {else}
        <a href="post.php?id={$post.id}">{$post.title}</a>
    {/if}
 {/foreach}

{include file="footer.tpl"}

Aquí la vista se encarga de toda la nueva lógica para la visualización de las entradas populares. El controlador y el modelo no necesita saber nada acerca de ese cambio. Es puramente lógica de presentación. La subpágina lista sigue se muestran como lo hacía antes.

Por último, nos gustaría cambiar lo popular post. En lugar de estar basado en el número de accesos a una página que tiene, nos gustaría que se basa en el número de comentarios de un post conseguí. Podemos aplicar ese cambio en el modelo:

post_model.php

class post_model {
    public function get_popular($number) {
        $sql = "SELECT * , COUNT(comments.id) as comment_count
                FROM posts 
                INNER JOIN comments ON comments.post_id = posts.id
                ORDER BY comment_count DESC 
                LIMIT $number";
        $result = mysql_query($sql);
        while($row = mysql_fetch_assoc($result)) {
            $array[] = $row;
        }
        return $array;
    } 
}

Hemos aumentado la complejidad de la popular "post" de la lógica. Sin embargo, una vez que hemos hecho este cambio en el modelo, en un solo lugar, la nueva lógica se aplica en todas partes. La página de inicio y la subpágina, sin otras modificaciones, ahora mostrará las entradas populares basados en los comentarios. Nuestro diseñador no necesita estar involucrados en esto. El marcado no se ve afectada.

Con suerte, esto proporciona un ejemplo de cómo la separación de las preocupaciones de los datos de la lógica, la lógica de la aplicación, y la lógica de presentación, puede hacer que el desarrollo de la aplicación más fácil. Los cambios en un área tienden a tener un menor impacto en otras áreas.

Siguiendo esta convención no es una varita mágica que automáticamente va a hacer que tu código sea perfecto. Y usted, sin duda, vienen a través de cuestiones en las que es mucho menos claro que la separación debe ser. En el final, es todo acerca de la gestión de la complejidad dentro de la aplicación.

Usted debe dar un montón de vueltas a cómo construir sus modelos. ¿Qué tipo de interfaces que proporcionan (véase Gregorio respuesta respecto de los contratos)? ¿Qué formato de datos que hace el controlador y la vista esperar a trabajar con? Pensar acerca de estas cosas antes de tiempo va a facilitar las cosas en el camino.

También, puede haber cierta sobrecarga cuando se inicia un proyecto para conseguir todas estas piezas que trabajan muy bien juntos. Hay muchos marcos que proporcionan los bloques de construcción de modelos, controladores, la plantillas de los motores, la url de enrutamiento, y más. Ver muchos otros puestos en MODO de sugerencias en PHP frameworks MVC. Estos marcos se pondrá en funcionamiento pero como el desarrollador se encarga de la gestión de la complejidad y el cumplimiento de una separación de preocupaciones.

Yo también tenga en cuenta que los fragmentos de código anteriores son sólo ejemplos simplificados. Se puede (lo más probable) tiene errores. Sin embargo, son muy similares en estructura al código que uso en mis propios proyectos.

3voto

Gregory A Beamer Puntos 10975

No estoy seguro de que puedo conducir a que el agua se wat para beber, pero creo que puedo responder algunas de sus inquietudes.

En primer lugar, en MVC, el modelo y la vista tienen algo de interacción, pero la vista es realmente junto a contrato y no a la aplicación. Usted puede cambiar a otros modelos que se adhieren al mismo contrato y todavía será capaz de utilizar la vista. Y, si lo piensas, tiene sentido. Un usuario tiene un nombre y apellido. Probablemente él también tiene un nombre de inicio de sesión y una contraseña, aunque usted puede o no puede vincular a la "contrato" de lo que un usuario es. El punto es que, una vez que usted determina lo que un usuario es, es poco probable que cambie mucho. Usted podría añadir algo, pero es poco probable que usted va a tomar distancia que a menudo.

En la vista, han punteros para el modelo que se adhiere a ese contrato, pero puedo usar un objeto simple:

 public class User
 {
    public string FirstName;
    public string LastName;
 }

Sí, me doy cuenta de campos públicos son malos. :-) Yo también puede utilizar una tabla de datos como un modelo, como el tiempo que expone Nombre y Apellidos. Puede que no sea el mejor ejemplo, pero el punto es que el modelo no está vinculado a la vista. La vista es atado a un contrato y el modelo en particular se adhiere a ese contrato.

No he oído hablar de que cada objeto debe tener su propia interfaz de usuario. Esencialmente hay dos tipos de objetos: el estado y comportamiento. He visto ejemplos que tienen tanto el estado y el comportamiento, sino que generalmente se encuentran en los sistemas que no son comprobables, que yo no soy aficionado. En última instancia, cada objeto de estado deben ser expuestos a algún tipo de interfaz de usuario para evitar QUE obliga a las personas a manejar todas las actualizaciones directamente en un almacén de datos, tal vez, pero tienen su propia interfaz de usuario? Me tendría que ver en una explicación para tratar de entender lo que el usuario está haciendo.

Como para el SoC, la reasaon a un paquete de cosas claramente es la capacidad para cambiar las capas/niveles sin tener que reescribir todo el sistema. En general, la aplicación es realmente situado en el nivel empresarial, de forma que la parte no puede ser fácilmente desactivado. Los datos y la interfaz de usuario debe ser bastante fácil de cambiar en un sistema bien diseñado.

Tan lejos como los libros en la comprensión de la programación orientada a objetos, en general me gustan los libros en los patrones, ya que son más prácticos maneras de entender los conceptos. Usted puede encontrar el primer material en la web. Si quieres un idioma agnóstico libro de patrones, y pensar un poco geek, la banda de los Cuatro libro es un buen lugar para empezar. Para los más creativos, yo diría que Hasta los Jefes de Patrones de Diseño.

2voto

Jack Ryan Puntos 5257

El problema con la idea de que todos sus objetos de saber cómo mostrar a sí mismos es que cada objeto sólo se puede mostrar en una forma. ¿Qué ocurre si usted desea proporcionar una vista de detalle de un usuario, y una vista de resumen. ¿Qué ocurre si usted desea mostrar una vista que combina un número de objetos (usuarios y sus direcciones asociadas, por ejemplo). Si usted separado de los objetos de negocio (usuarios) de las cosas que sabe cómo mostrar a ellos, entonces usted no tiene más código para escribir, usted acaba de separar en diferentes lugares.

Esto hace que el software sea más fácil de mantener porque si un objeto de usuario se comporta incorrectamente, usted sabe que es el usuario, si es que no se muestra correctamente, usted sabe que es la vista. En la situación en la que usted necesita para proporcionar una nueva interfaz para su aplicación (dicen que decide dar un nuevo aspecto y estilo para navegadores móviles), entonces usted no necesita cambiar su objeto de usuario en todos, se agrega un nuevo objeto que sabe cómo procesar el objeto de usuario de un navegador móvil.

SÓLIDOS principios proporcionará un buen razonamiento para esto, aquí es relativamente concisa vistazo a estas. Me temo que yo no tengo un libro a mano que lo resume bien, pero la experiencia me ha enseñado que es más fácil escribir código nuevo que es para actualizar el viejo código, y así los diseños que favorezcan a los pequeños modular de clases que se conectan para lograr lo que se necesita, si bien es más difícil para el diseño de la parte delantera, son mucho más fáciles de mantener en el largo plazo. Es genial ser capaz de escribir un nuevo renderizador de un objeto de usuario, sin tener que profundizar en los mecanismos internos de ese objeto.

2voto

MrValdez Puntos 5159

Cualquiera puede proponer un argumento [...] que explica por qué MVC es una buena idea?

Se mantiene sano al ayudarle a recordar lo que su código no porque están aislados unos de otros.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X