31 votes

Séparation des préoccupations; MVC; Pourquoi?

Je suis en train de lire sur OO avant de m'embarquer sur mon prochain projet d'envergure. Pour vous donner quelques conseils rapides, fond, je suis un développeur PHP, en travaillant sur des applications web.

Un domaine qui m'intéresse particulièrement est l'Interface Utilisateur; en particulier, la façon de construire le présent et le connecter à mon OO "modèle".

J'ai fait un peu de lecture sur ce domaine. L'un de mes favoris est ceci: La création d'interfaces utilisateur pour les systèmes orientés objet

"Tous les objets doivent fournir leur propre INTERFACE utilisateur"

Penser à mon problème, je peux voir ce qui fonctionne bien. - Je construire mon "utilisateur" de l'objet à représenter quelqu'un qui s'est connecté à mon site web, par exemple. Une de mes méthodes est alors "display_yourself" ou similaire. Je peux utiliser ce tout au long de mon code. Peut-être pour commencer ce sera juste leur nom. Plus tard, si j'ai besoin de s'adapter à montrer leur nom+petit avatar, je peux juste mettre à jour cette une méthode et d'hé-hop, mon application est mise à jour. Ou si j'ai besoin de faire leur nom un lien vers leur profil, hé presto je peux mettre à jour facilement à partir d'un seul endroit.

En termes de OO système; je pense que cette approche fonctionne bien. La recherche sur d'autres StackOverflow fils, j'ai trouvé ce en vertu de la "Séparation des Préoccupations": Soc

"En informatique, la séparation de préoccupations (SoC) est le processus de la rupture d'un programme d'ordinateur, en caractéristiques distinctes qui se chevauchent dans le fonctionnalité aussi peu que possible. Un le souci est un morceau d'intérêt ou de l'accent dans un programme. Généralement, les préoccupations sont synonymes de fonctionnalités ou de comportements. Les progrès vers la SoC est traditionnellement réalisé par la modularité et l'encapsulation, avec l' aider de se cacher de l'information."

À mon esprit que j'ai atteint cet objectif. Mon objet utilisateur se cache tout, c'est de l'information. Je n'ai pas de places dans mon code où je dis que $user->get_user_name() avant de l'afficher.

Toutefois, cela semble aller à l'encontre de ce que d'autres personnes semblent penser que les "meilleures pratiques".

Pour citer les "sélectionnés" (verte) la réponse à la même question:

"La séparation des préoccupations est de garder le code de chacune de ces préoccupations séparé. Modification de l'interface ne devrait pas avoir besoin de changer la code de la logique métier, et vice versa. Modèle-Vue-Contrôleur (MVC) conception modèle est un excellent exemple de la séparation de ces préoccupations pour mieux logiciel de maintenance."

Pourquoi cela fait-il pour meilleur logiciel de maintenance? Sûrement avec MVC, de mon point de Vue a savoir énormément sur le Modèle? Lire la JavaWorld article pour une discussion détaillée sur ce point: La création d'interfaces utilisateur pour les systèmes orientés objet

De toute façon... faire pour le moment, enfin!

1. Peut-on recommander tous les livres discuter de cela en détail? Je ne veux pas d'un MVC livre; je ne suis pas vendu sur MVC. Je veux un livre qui traite de OO / UI les problèmes potentiels, le potentiel solutuions etc.. (peut-être y compris MVC) Arthur Riel de Conception Orientée Objet Heuristique

touche sur elle (et est un excellent livre!), mais je veux quelque chose qui va plus dans le détail.

2. Quelqu'un peut-il mettre en avant un argument qui est aussi bien expliqué que Allen Holub est JavaWorld article qui explique pourquoi MVC est une bonne idée?

Merci beaucoup pour toute personne qui peut m'aider à parvenir à une conclusion sur ce point.

33voto

Boden Points 2242

C'est un échec, dans la façon dont la programmation orientée objet est souvent enseigné, à l'aide d'exemples comme rectangle.draw() et de dinosaures.show() qui a absolument aucun sens.

Vous avez presque répondu à votre propre question, quand vous parlez d'avoir une classe d'utilisateur qui s'affiche.

"Plus tard, si j'ai besoin de s'adapter à montrer leur nom+petit avatar, je peux juste mettre à jour cette une méthode et d'hé-hop, mon application est mise à jour."

Pensez juste ce petit morceau pour le moment. Maintenant, jetez un oeil à Débordement de Pile et de l'avis de tous les lieux où votre nom d'utilisateur s'affiche. Est-il le même dans chaque cas? Non, en haut, vous avez juste obtenu une enveloppe à côté de votre nom d'utilisateur suivi de votre réputation et des badges. Dans une question au sujet que vous avez votre avatar, suivi de votre nom d'utilisateur avec votre réputation et badges dessous. Pensez-vous qu'il y est un objet utilisateur avec des méthodes comme getUserNameWithAvatarInFrontOfItandreputationandbadgesunderneath() ? Nah.

Un objet avec les données qu'il représente et les méthodes qui agissent sur ces données. Votre objet utilisateur aura probablement firstName et lastName membres, et les getters pour récupérer les pièces. Il pourrait aussi y avoir un confort méthode toString() (en Java termes) qui retourne le nom de l'utilisateur dans un format commun, comme le prénom suivi d'un espace, puis le nom de famille. A côté de cela, l'utilisateur de l'objet ne doit pas faire grand chose d'autre. C'est au client de décider ce qu'elle veut faire avec l'objet.

Prenons l'exemple que vous nous avez fournies avec l'utilisateur de l'objet, et ensuite réfléchir à comment vous pourriez faire ce qui suit si vous avez construit une "INTERFACE utilisateur" en elle:

  1. Créer un export CSV montrant tous les utilisateurs, classées par ordre de nom de famille. E. g. Lastname, Firstname.
  2. Fournir à la fois un poids lourd de l'interface graphique et une interface Web pour travailler avec l'utilisateur de l'objet.
  3. Afficher un avatar à côté du nom d'utilisateur en un seul endroit, mais seulement de montrer le nom de l'utilisateur dans un autre.
  4. Fournir des flux RSS liste des utilisateurs.
  5. Afficher le nom d'utilisateur gras dans un seul endroit, en italique dans l'autre, et comme un lien hypertexte dans encore un autre endroit.
  6. Montrer à l'utilisateur initial du milieu, le cas échéant.

Si vous pensez au sujet de ces exigences, elles se résument toutes à la fourniture d'un objet utilisateur qui ne concerne que les données qu'il devrait être concernés par. Il ne faut pas essayer d'être tout pour tout le monde, il faut juste prévoir un moyen d'obtenir les données de l'utilisateur. C'est à chacun de la de nombreux points de vue vous permettra de créer de décider comment il veut afficher les données de l'utilisateur.

Votre idée au sujet de la mise à jour de code dans un seul endroit pour mettre à jour votre point de vue dans de nombreux endroits en est une bonne. C'est encore possible sans coucher avec des choses à un trop faible niveau. Vous pouvez créer des widgets classes qui encapsulent les différents points de vue communs de "trucs", et de les utiliser tout au long de votre afficher le code.

25voto

GloryFish Points 3388

Voici l'approche que je prends lors de la création de sites web en PHP à l'aide d'un MVC/séparation des préoccupations modèle:

Le cadre-je utiliser a trois parties principales:

  • Modèles - les Classes PHP. J'ai ajouter des méthodes à eux de récupérer et de sauvegarder les données. Chaque modèle représente un type distinct de l'entité dans le système: les utilisateurs, les pages, billets de blog
  • Vues - Smarty templates. C'est là que le code html de vie.
  • Contrôleurs - classes PHP. Ce sont les cerveaux de l'application. Généralement url du site d'appeler des méthodes de la classe. example.com/user/show/1 serait invoquer l' $user_controller->show(1) de la méthode. Le contrôleur récupère des données le modèle et la donne à la vue.

Chacune de ces pièces a un travail spécifique ou d'une "situation préoccupante". Le modèle dela tâche est de fournir une interface propre pour les données. Généralement, les données du site est stocké dans une base de données SQL. J'ai ajouter des méthodes pour le modèle pour l'extraction de données et la sauvegarde des données dans.

La vue's de l'emploi est pour l'affichage des données. Toutes les balises HTML va dans la vue. Une logique de gestion des zèbres de segmentation pour une table de données dans la vue. Code pour gérer le format d'une date doit être affichée en va dans la vue. J'ai comme l'utilisation de Smarty templates pour les vues, car il offre quelques fonctionnalités intéressantes pour gérer des choses comme ça.

Le contrôleur dela tâche est d'agir comme un intermédiaire entre l'utilisateur, le modèle et la vue.

Regardons un exemple de la façon dont ceux-ci viennent ensemble, et où les avantages de mensonge:

Imaginez un simple site de blog. La pièce principale de données est un post. Aussi, imaginez que le site garde une trace du nombre de fois qu'un poste est affiché. Nous allons créer une table SQL pour que:

posts
id date_created title body hits

Maintenant, supposons que vous souhaitez afficher 5 messages les plus populaires. Voici ce que vous pourriez voir dans un non application 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 />";
}

Cet extrait est assez simple et fonctionne bien si:

  1. C'est le seul endroit où vous souhaitez afficher les messages les plus populaires
  2. Vous ne voulez jamais à changer la façon dont il semble
  3. Ne jamais vous décidez de changer de ce qu'est un "populaire post" est

Imaginez que vous souhaitez afficher les 10 messages les plus populaires sur la page d'accueil et les 5 les plus populaires dans un encadré sur les sous-pages. Maintenant, vous avez besoin soit de dupliquer le code ci-dessus, ou le mettre dans un fichier inclus avec la logique pour vérifier où il est affiché.

Que faire si vous voulez mettre à jour le balisage de la page d'accueil pour ajouter un "nouveau post" classe à des postes qui ont été créés aujourd'hui?

Supposons que vous décidez qu'un post est populaire parce qu'il a beaucoup de commentaires, pas de hits. La base de données va changer pour refléter cela. Maintenant, chaque endroit dans votre application qui montre populaire postes doivent être mis à jour pour refléter la nouvelle logique.

Vous commencez à voir une boule de neige de la complexité de la forme. Il est facile de voir comment les choses peuvent devenir de plus en plus difficile à maintenir sur la durée d'un projet. Aussi, tenir compte de la complexité lorsque plusieurs développeurs travaillent sur un projet. Le designer doit-il se concerter avec le développeur de base de données lors de l'ajout d'une classe à la sortie?

En prenant une approche MVC et l'application d'une séparation des préoccupations au sein de votre application peut atténuer ces problèmes. Idéalement, nous voulons nous séparer en trois zones:

  1. les données de la logique
  2. la logique de l'application
  3. et la logique d'affichage

Nous allons voir comment faire cela:

Nous allons commencer avec le modèle. Nous allons avoir un $post_model de la classe et de lui donner une méthode appelée get_popular(). Cette méthode retourne un tableau de postes. En outre, nous allons lui donner un paramètre pour spécifier le nombre de postes à retourner:

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;
    } 
}

Maintenant pour la page d'accueil, nous avons un contrôleur, nous allons l'appeler "maison". Imaginons que nous avons une url schéma de routage qui appelle de notre contrôleur de la page d'accueil est demandée. C'est le travail est d'obtenir le populaire postes et de les offrir à la vue correcte:

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');
}

Maintenant, nous allons voir ce que la vue ressemblerait à:

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"}

Maintenant, nous avons les morceaux de base de notre application et vous pouvez voir la séparation des préoccupations.

Le modèle est concerné par l'obtention des données. Il sait à propos de la base de données, il sait à propos de requêtes SQL et de LIMITER les déclarations. Il sait qu'il doit remettre un joli tableau.

Le contrôleur sait au sujet de la demande de l'utilisateur, qu'ils sont à la recherche à la page d'accueil. Il sait que la page d'accueil doit présenter 10 populaire postes. Il récupère les données à partir du modèle et donne à la vue.

La vue sait qu'un tableau de postes devrait être affiché comme une série d'acor balises avec les balises de saut après eux. Il sait qu'un post a un titre et un numéro d'identification. Elle sait que c'est un post du titre devrait être utilisée pour le texte d'ancre et que les postes id doit être utilisé dans le href. Il sait qu'il devrait y avoir un en-tête et pied de page indiqué sur la page.

Il est également important de mentionner que chaque morceau ne pas savoir.

Le modèle ne sait pas que les populaires les messages sont affichés sur la page d'accueil.

Le contrôleur et la vue ne sais pas que les messages sont stockés dans une base de données SQL.

Le contrôleur et le modèle ne savent pas que chaque lien vers un post sur la page d'accueil doit avoir une étiquette de rupture après.

Donc, dans cet état, nous avons établi une claire séparation des préoccupations entre les données de la logique (le modèle), la logique de l'application (le contrôleur), et une logique d'affichage (la vue). Alors maintenant, quoi? Nous avons pris un court, simple bout de code PHP et il s'est brisé en trois confusion des fichiers. Qu'est-ce à nous donner?

Regardons comment le fait d'avoir une séparation des préoccupations qui peuvent nous aider avec les questions mentionnées ci-dessus. Pour rappel, nous voulons:

  1. Spectacle populaire postes dans un encadré sur les sous-pages
  2. Mettre en évidence de nouveaux postes avec un supplément de classe css
  3. Modifier la définition de "populaire post"

Pour afficher le populaire postes dans une barre latérale, nous allons ajouter deux fichiers de notre page:

Une sous-page de contrôleur...

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');
}

...et une sous-page modèle:

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"}

Le nouveau volet de contrôleur sait que la page doit afficher uniquement les 5 populaire postes. La sous-page afficher sait que les sous-pages, devrait mettre la liste des postes à l'intérieur d'un div sidebar.

Maintenant, sur la page d'accueil, nous voulons mettre en évidence de nouveaux postes. Nous pouvons y arriver en modifiant la page d'accueil.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"}

Ici, la vue s'occupe de toutes les nouvelle logique pour l'affichage populaires postes. Le contrôleur et le modèle n'a pas besoin de savoir quelque chose au sujet de ce changement. C'est purement logique d'affichage. La sous-page de la liste continue de se manifester comme il le faisait avant.

Enfin, nous aimerions changer ce populaire post est. Au lieu d'être basée sur le nombre de visites à une page arrivés, nous aimerions qu'il soit basé sur le nombre de commentaires d'un post a obtenu. Nous pouvons appliquer cette modification sur le modèle:

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;
    } 
}

Nous avons augmenté la complexité de la "populaire post" de la logique. Cependant, une fois que nous avons fait ce changement dans le modèle, à un endroit, la nouvelle logique est appliquée partout. La page d'accueil et la page, n'ayant pas d'autres modifications, affiche désormais populaire postes sur la base des commentaires. Notre concepteur n'a pas besoin d'être impliqué dans ce domaine. Le balisage n'est pas affectée.

Nous espérons que cela vous fournit un exemple éloquent de la façon de séparer les préoccupations des données de la logique, de la logique de l'application, et la logique d'affichage, peuvent rendre le développement de votre application plus facile. Les changements dans un domaine ont tendance à avoir moins d'impact sur les autres zones.

Suite à cette convention n'est pas une solution magique qui va automatiquement votre code parfait. Et vous allez sans doute trouver des problèmes là où il est beaucoup moins claire dans la mesure où la séparation devrait être. En fin de compte, il est tout au sujet de la gestion de la complexité au sein de l'application.

Vous devez donner beaucoup de pensée à la façon dont vous construire vos modèles. Quel genre d'interfaces qu'ils fournissent (voir Grégoire de répondre, en ce qui concerne les contrats)? Ce format de données le contrôleur et la vue s'attendre à travailler avec? En pensant à ces choses à l'avance rendra les choses plus faciles en bas de la route.

Aussi, il peut y avoir une surcharge lors du démarrage d'un projet pour obtenir l'ensemble de ces éléments travaillent ensemble à merveille. Il y a beaucoup de cadres qui fournissent les blocs de construction pour les modèles, les contrôleurs, la création de modèles de moteurs, le routage d'url, et plus encore. Voir de nombreux autres postes sur DONC pour des suggestions sur les frameworks PHP MVC. Ces cadres de vous lever et courir, mais vous en tant que le développeur en charge de la gestion de la complexité et de l'application d'une séparation des préoccupations.

Je vais aussi noter que les extraits de code ci-dessus sont quelques exemples très simplifiés. Ils peuvent (plus probable) ont des bugs. Cependant, ils sont très similaires dans leur structure pour le code que j'utilise dans mes propres projets.

3voto

Gregory A Beamer Points 10975

Je ne suis pas sûr que je peut vous conduire à de l'eau que vous wat à boire, mais je pense que je peux répondre à certaines de vos préoccupations.

Tout d'abord, MVC, le modèle et la vue ne avoir une certaine interaction, mais la vue est vraiment couplé à un contrat et non à la mise en œuvre. Vous pouvez passer à d'autres modèles, qui adhèrent à la même contrat, et encore être en mesure d'utiliser la vue. Et, si vous pensez à ce sujet, cela fait sens. Un utilisateur a un nom et de prénom. Il dispose probablement d'un nom de connexion et un mot de passe, bien que vous pourrait ou ne pourrait pas le lien pour le "contrat" de ce que l'utilisateur est. Le point est, une fois que vous déterminer ce que l'utilisateur est, il est peu probable que beaucoup de changement. Vous pouvez ajouter quelque chose, mais il est peu probable que vous allez prendre de suite que souvent.

Dans la vue, vous avez des pointeurs vers le modèle qui adhère à ce contrat, mais je peux utiliser un simple objet:

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

Oui, je me rends compte du public les champs sont mauvais. :-) Je peux aussi utiliser un DataTable comme un modèle, tant qu'il expose FirstName et LastName. Peut-être pas le meilleur exemple, mais le point est que le modèle n'est pas lié à la vue. La vue est liée à un contrat et le modèle particulier adhère à ce contrat.

Je n'ai pas entendu de chaque objet doit avoir sa propre INTERFACE utilisateur. Il existe essentiellement deux types d'objets: état et le comportement. J'ai vu des exemples qui ont à la fois l'état et le comportement, mais ils sont généralement dans des systèmes qui ne sont pas très vérifiable, que je ne suis pas friand des. En fin de compte, chaque état de l'objet doit être exposé à une certaine forme de l'INTERFACE utilisateur, pour éviter de forcer les gens à gérer toutes les mises à jour directement dans une banque de données, peut-être, mais qui ont leur propre INTERFACE utilisateur? Je dois voir qui écrit dans une explication pour essayer de comprendre ce que l'utilisateur est en train de faire.

Comme pour le SoC, le reasaon à l'emballage des choses nettement, c'est la capacité de passer d'couches/niveaux sans avoir à réécrire l'ensemble du système. En général, l'application est vraiment situé dans la couche d'entreprise, de sorte que la pièce ne peuvent pas être mis à l'écart. Les données et l'INTERFACE utilisateur devrait être assez facile de basculer dans un système bien conçu.

Aussi loin que les livres sur la compréhension de la programmation orientée objet, j'ai tendance à aimer les livres sur les modèles, car ils sont plus pratiques manières de comprendre les concepts. Vous pouvez trouver l'apprêt sur le web. Si vous voulez une langue agnostique livre de patron, et de penser un peu geek, le Gang of four est un bon endroit pour commencer. Pour les plus créatifs, je dirais dirige les Modèles de Conception.

2voto

Jack Ryan Points 5257

Le problème avec l'idée que tous vos objets de savoir comment faire pour afficher eux-mêmes, c'est que chaque objet ne peut être affiché que dans un seul sens. Qu'advient-il si vous souhaitez fournir une vue de détail d'un utilisateur, et une vue de synthèse. Qu'advient-il si vous souhaitez afficher une vue qui fusionne un certain nombre d'objets (utilisateurs et de leurs adresses par exemple). Si vous séparer de votre entreprise objets (utilisateurs) à partir des choses qui sais comment faire pour les afficher ensuite vous n'avez plus de code à écrire, vous venez de vous séparer en différents endroits.

Cela rend le logiciel plus facile à maintenir car si un objet utilisateur est de se comporter de manière incorrecte, vous savez que c'est l'utilisateur, si elle ne s'affiche pas correctement, vous savez que c'est la vue. Dans la situation où vous avez besoin de fournir une nouvelle interface de votre application (que vous décidiez de vous offrir un nouveau look et la sensation pour les navigateurs mobiles), alors vous n'avez pas besoin de changer votre objet utilisateur à tous, vous ajoutez un nouvel objet qui sait comment rendre l'objet utilisateur pour un navigateur mobile.

De SOLIDES principes de fournir quelques bonnes raisons pour cela, ici, est relativement concis regardez ces. Je crains que je n'ai pas de livre à la main qui résume très bien, mais l'expérience m'a appris qu'il est plus facile d'écrire du nouveau code que pour la mise à jour de l'ancien code, et donc que les conceptions de favoriser les petites modulaire classes plug ensemble pour réaliser ce qui est nécessaire, tandis que les plus difficile de la conception jusqu'à l'avant, sont beaucoup plus faciles à maintenir dans le long terme. C'est génial d'être en mesure d'écrire un nouveau moteur de rendu pour un objet utilisateur, sans jamais avoir à se plonger dans les entrailles de cet objet.

2voto

MrValdez Points 5159

Quelqu'un peut-il avancer un argument [...] qui explique pourquoi MVC est une bonne idée?

Il vous garde sain d'esprit en vous aidant à vous souvenir de ce que fait votre code car ils sont isolés les uns des autres.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X