148 votes

AngularJS : Modèle de conception compréhension

AngularJS: Shared publicly - Juil 19, 2012

MVC vs MVVM vs MVP. Ce qu'est un sujet controversé que de nombreux développeurs vous pouvez passer des heures et des heures à débattre et à argumenter à propos.

Depuis plusieurs années, AngularJS était plus proche de MVC (ou plutôt l'un de ses côté client variantes), mais au fil du temps et grâce à de nombreux refactorings d'api et d'améliorations, il est maintenant plus proche de MVVM – le $scopeobjet pourrait être considéré comme le ViewModel qui est décoré par un la fonction que nous appelons un Contrôleur.

Être en mesure de catégoriser un cadre et de le placer dans l'un des MV* seaux a certains avantages. Il peut aider les développeurs à obtenir plus à l'aise avec ses api en le rendant plus facile de créer un modèle mental qui représente l'application que se construit avec le cadre. Il peut aussi aider à établir la terminologie qui est utilisée par les développeurs.

Cela dit, je préfère voir les développeurs à créer de kick-ass, les applications qui sont bien conçu et suivez la séparation des préoccupations, que de les voir déchets de temps à discuter sur MV* non-sens. Et pour cette raison, je déclare par la présente AngularJS pour être MVW cadre - Modèle-Vue-de-Quoi. Où Tout Ce Que signifie "tout ce qui fonctionne pour vous".

Angulaire vous donne beaucoup de flexibilité, afin de bien séparer la présentation la logique de la logique métier et la présentation de l'état. Veuillez utiliser le carburant votre productivité et la maintenabilité de l'application plutôt que d'chauffée les discussions à propos de choses qu'à la fin de la journée, n'a pas d'importance qui beaucoup.

Existe-il des recommandations ou des lignes directrices pour la mise en œuvre de AngularJS MVW (Model View Quoi que ce soit) modèle de conception dans des applications côté client?

222voto

Artem Platonov Points 879

Grâce à une énorme quantité de précieuses sources, j'ai quelques recommandations générales pour la mise en œuvre de composants dans les applications AngularJS:


Contrôleur

  • Le contrôleur doit être juste un intermédiaire entre le modèle et la vue. Essayez de le rendre aussi mince que possible.

  • Il est fortement recommandé d' éviter la logique métier de contrôleur. Il doit être déplacé pour modèle.

  • Contrôleur peut communiquer avec d'autres contrôleurs à l'aide de la méthode d'invocation (possible lorsque les enfants veut communiquer avec un parent) ou $émettent, $diffusion et $sur les méthodes. Émis et diffusé les messages doivent être maintenus à un minimum.

  • Contrôleur doit se soucient pas de présentation ou de manipulation du DOM.

  • Essayez d' éviter imbriqués les contrôleurs. Dans ce cas, contrôleur de parent est interprété comme modèle. Injecter des modèles de services partagés de la place.

  • Champ d'application dans le contrôleur doit être utilisé pour la liaison de modèle avec vue et
    l'encapsulation Modèle de Vue que pour le Modèle de Présentation modèle de conception.


Portée

Traiter portée en lecture seule dans les modèles et écrire uniquement dans les contrôleurs. Le but de la portée est de se référer au modèle, de ne pas être le modèle.

Lorsque vous faites bidirectionnel de liaison (ng-model) assurez-vous de ne pas lier directement à la portée des propriétés.


Modèle

Modèle en AngularJS est un singleton défini par le service.

Le modèle fournit un excellent moyen pour séparer les données et de les afficher.

Les modèles sont des candidats de choix pour les tests unitaires, comme ils ont généralement exactement une dépendance (une forme de manifestation de l'émetteur, dans le cas de l' $rootScope) et contiennent très testable domaine de la logique.

  • Modèle doit être considéré comme une mise en place de l'unité en question. Elle est basée sur une seule responsabilité de principe. L'unité est une instance qui est responsable de son propre champ d'application de la logique que peut représenter la seule entité dans le monde réel et le décrire dans le monde de programmation en termes de données et de l'état.

  • Le modèle doit encapsuler les données de votre application et de fournir une API pour accéder et manipuler des données.

  • Le modèle devrait être portable de sorte qu'il peut facilement être transporté sur similaires application.

  • En isolant l'unité logique dans votre modèle, vous ont rendu plus facile les localiser, de les mettre à jour et conserver.

  • Le modèle peut utiliser des méthodes plus générales sur les modèles globaux qui sont communes pour l'ensemble de l'application.

  • Essayez d'éviter de composition d'autres modèles dans votre modèle à l'aide de l'injection de dépendance si elle n'est pas vraiment dépendant de la diminution de composants de couplage et l'augmentation de l'unité de la testabilité et de la convivialité.

  • Essayez d'éviter d'utiliser des écouteurs d'événement dans les modèles. Il les rend plus difficiles à tester et généralement tue des modèles en termes de la seule responsabilité de principe.

Mise En Œuvre Du Modèle

En tant que modèle doit encapsuler la logique en termes de données et de l'état, il devrait l'architecture de restreindre l'accès à ses membres ainsi nous pouvons garantir le couplage lâche.

La manière de le faire en application AngularJS est de la définir à l'aide de l'usine type de service. Cela va nous permettre de définir des propriétés privées et des méthodes très facile et aussi de retour publiquement accessibles dans le seul endroit qui le rendra vraiment lisible pour le développeur.

Un exemple:

angular.module('search')
.factory( 'searchModel', ['searchResource', function (searchResource) {

  var itemsPerPage = 10,
  currentPage = 1,
  totalPages = 0,
  allLoaded = false,
  searchQuery;

  function init(params) {
    itemsPerPage = params.itemsPerPage || itemsPerPage;
    searchQuery = params.substring || searchQuery;
  }

  function findItems(page, queryParams) {
    searchQuery = queryParams.substring || searchQuery;

    return searchResource.fetch(searchQuery, page, itemsPerPage).then( function (results) {
      totalPages = results.totalPages;
      currentPage = results.currentPage;
      allLoaded = totalPages <= currentPage;

      return results.list
    });
  }

  function findNext() {
    return findItems(currentPage + 1);
  }

  function isAllLoaded() {
    return allLoaded;
  }

  // return public model API  
  return {
    /**
     * @param {Object} params
     */
    init: init,

    /**
     * @param {Number} page
     * @param {Object} queryParams
     * @return {Object} promise
     */
    find: findItems,

    /**
     * @return {Boolean}
     */
    allLoaded: isAllLoaded,

    /**
     * @return {Object} promise
     */
    findNext: findNext
  };
});

La création de nouvelles instances

Essayez d'éviter d'avoir une usine qui renvoie une nouvelle mesure de fonction comme cela commence à décomposer l'injection de dépendance et de la bibliothèque va se comporter maladroitement, en particulier pour les tiers.

Une meilleure façon d'accomplir la même chose est d'utiliser de l'usine comme une API pour retourner une collection d'objets avec des méthodes getter et setter attaché à eux.

angular.module('car')
 .factory( 'carModel', ['carResource', function (carResource) {

  function Car(data) {
    angular.extend(this, data);
  }

  Car.prototype = {
    save: function () {
      // TODO: strip irrelevant fields
      var carData = //...
      return carResource.save(carData);
    }
  };

  function getCarById ( id ) {
    return carResource.getById(id).then(function (data) {
      return new Car(data);
    });
  }

  // the public API
  return {
    // ...
    findById: getCarById
    // ...
  };
});

Modèle Global

En général, essayez d'éviter de telles situations et la conception de vos modèles correctement donc il peut être injecté dans le contrôleur et utilisés dans votre point de vue.

Dans le cas particulier de certaines méthodes nécessitent l'accessibilité globale à l'intérieur de l'application. Pour la rendre possible, vous pouvez définir la"commune de lapropriété $rootScope et le lier à commonModel lors de l'application de bootstrap:

angular.module('app', ['app.common'])
.config(...)
.run(['$rootScope', 'commonModel', function ($rootScope, commonModel) {
  $rootScope.common = 'commonModel';
}]);

Toutes vos méthodes globales vivent à moins de ‘commun' de la propriété. C'est une sorte d' espace de noms.

Mais ne définit pas de méthodes directement dans votre $rootScope. Cela peut entraîner un comportement inattendu lorsqu'il est utilisé avec ngModel la directive au sein de votre portée de vue, généralement jonchent votre portée et conduit à la portée des méthodes de questions primordiales.


Ressources

Ressources vous permet d'interagir avec différentes sources de données.

Devrait être mis en œuvre en utilisant une seule responsabilité de principe.

Dans le cas particulier, il est réutilisable proxy HTTP/JSON points de terminaison.

Les ressources sont injectés dans les modèles et assurer la possibilité d'envoyer et de récupérer des données.

Ressources de mise en œuvre

Une usine qui crée un objet de ressource qui vous permet d'interagir avec RESTful côté serveur des sources de données.

Le retour de l'objet de la ressource a des méthodes d'action qui fournissent de haut niveau des comportements, sans la nécessité d'interagir avec le faible niveau de $service http.


Services

À la fois modèle et des ressources sont des services.

Des Services sont pas associés, faiblement couplé unités de fonctionnalités qui sont autonomes.

Les Services sont une fonctionnalité qui Angulaire apporte à côté client applications web côté serveur, où les services ont été couramment utilisés pendant une longue période.

Services Angulaire applications sont substituables les objets qui sont fixés ensemble à l'aide de l'injection de dépendance.

Angulaire est livré avec différents types de services. Chacun avec son propre cas d'utilisation. Veuillez lire Comprendre les Types de Service pour plus de détails.

Essayer de tenir compte des grands principes de l'architecture de services dans votre application.

En général, selon les Services Web Glossaire:

Un service est un résumé de la ressource qui représente une capacité de de l'exécution de tâches qui forment un ensemble cohérent de fonctionnalités à partir du point de vue de fournisseurs de entités et les demandeurs d'entités. Pour être utilisé, un le service doit être réalisé par un fournisseur de béton de l'agent.


Côté Client, structure

En général partie client de l'application est découpée en modules. Chaque module doit être testable comme une unité.

Essayez de définir les modules en fonction de la fonctionnalité, de la fonctionnalité ou de la vue, et non pas par type. Voir Misko de présentation pour plus de détails.

Composants du Module peut être classiquement regroupés par types, tels que les contrôleurs, les modèles, les vues, les filtres, directives, etc.

Mais le module en lui-même reste réutilisable, transférable et vérifiables.

Il est également beaucoup plus facile pour les développeurs de trouver certaines parties de code et de toutes ses dépendances.

Veuillez consulter le Code de l'Organisation dans les Grandes AngularJS et des Applications JavaScript pour plus de détails.

Un exemple de dossiers structurants:

|-- src/
|   |-- app/
|   |   |-- app.js
|   |   |-- home/
|   |   |   |-- home.js
|   |   |   |-- homeCtrl.js
|   |   |   |-- home.spec.js
|   |   |   |-- home.tpl.html
|   |   |   |-- home.less
|   |   |-- user/
|   |   |   |-- user.js
|   |   |   |-- userCtrl.js
|   |   |   |-- userModel.js
|   |   |   |-- userResource.js
|   |   |   |-- user.spec.js
|   |   |   |-- user.tpl.html
|   |   |   |-- user.less
|   |   |   |-- create/
|   |   |   |   |-- create.js
|   |   |   |   |-- createCtrl.js
|   |   |   |   |-- create.tpl.html
|   |-- common/
|   |   |-- authentication/
|   |   |   |-- authentication.js
|   |   |   |-- authenticationModel.js
|   |   |   |-- authenticationService.js
|   |-- assets/
|   |   |-- images/
|   |   |   |-- logo.png
|   |   |   |-- user/
|   |   |   |   |-- user-icon.png
|   |   |   |   |-- user-default-avatar.png
|   |-- index.html

Bon exemple de l'angulaire de l'application de structuration est mis en œuvre par angulaires-app - https://github.com/angular-app/angular-app/tree/master/client/src

Ceci est également considéré par l'application moderne générateurs - https://github.com/yeoman/generator-angular/issues/109

5voto

Dmitri Zaitsev Points 1012

Un problème mineur en comparant aux grandes conseils en réponse de Artem, mais en termes de lisibilité du code, j’ai trouvé mieux définir l’API complètement à l’envers le objet, afin de réduire au minimum des allers-retours dans le code pour examiner les variables whevere sont définis :

Si le `` objet devient à la recherche de « trop de monde », c’est un signe que le Service fait trop.

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