Utiliser une couche de service avec MVC


13

Si un contrôleur devient trop gros et que l'instanciation du modèle commence à s'additionner, une couche de service peut être utilisée.

  • Si j'encapsule simplement la logique dans une classe de service, j'obtiendrai un tas de services avec une / deux méthodes. Cela ressemble à une odeur de code. Des bonnes pratiques à ce sujet?

  • Un service peut-il instancier des modèles?

  • Si un service instancie des modèles, les services ne peuvent pas être testés à l'unité. Ils ne peuvent être couverts que par des tests d'intégration?

Réponses:


25

Dans 'SOLID' le 'I' signifie Interface Segregation. L'idée de ce principe est de diviser les grandes interfaces en plus petites, plus modulaires. Dans MVC, le service aurait normalement une interface sur laquelle le contrôleur s'appuierait. Vous ne voulez pas que vos contrôleurs soient informés de la mise en œuvre concrète de ce service. Par conséquent, un tas de services avec une ou deux méthodes est une bonne chose à avoir.

Les services renvoient normalement les DTO dans les grandes applications ou les modèles de domaine directement dans les petites applications. Les DTO signifient normalement plus de travail, mais une meilleure séparation des préoccupations. Le flux typique est:

  • Le contrôleur appelle le service
  • Le service renvoie un objet (que ce soit un DTO, un modèle de domaine ou autre chose)
  • Le contrôleur mappe le modèle DTO / domaine à un modèle de vue

Le mappage peut être fait manuellement, mais la plupart des développeurs préfèrent utiliser le cadre de mappage automatique tel que Automapper parce que nous n'aimons pas écrire du code de plomberie et nous pouvons être assez paresseux :-)

http://en.wikipedia.org/wiki/Interface_segregation_principle

https://github.com/AutoMapper/AutoMapper

L'une des nombreuses discussions sur stackoverflow concernant l'utilisation des DTO et des modèles de domaine: /programming/2680071/dto-or-domain-model-object-in-the-view-layer


1
Je serais prudent en utilisant un mappeur automatique ici uglybugger.org/software/post/…
Daniel Little

AutoMapper est livré avec une fonctionnalité de test unitaire intégrée qui vous permet de vérifier toutes vos routines de mappage avec une seule ligne. L'auteur de cet article n'a pas mentionné cela.
CodeART

Mais il le sait et l'a utilisé. Les commentaires vont un peu là-dessus.
Daniel Little

2
Beaucoup de classes avec seulement une ou deux méthodes signifient généralement qu'elles ne sont pas cohérentes. Une couche de service, si elle existe, doit être mince, l'essentiel de la logique se trouvant dans les modèles. Il semble plutôt inutile de lier une vue à un objet muet qui n'est rien de plus qu'un sac de propriété. Le modèle dans MVC devrait être le modèle de domaine riche, pas un modèle anémique martinfowler.com/bliki/AnemicDomainModel.html
Andy

3

Dans MVC, le modèle n'est pas seulement un DTO ou un ensemble de gestionnaires / services, il est censé représenter les concepts que votre application modélise. Vous pouvez considérer cela comme l'ensemble du domaine ou la logique métier, y compris l'état et les comportements. Maintenant que nous savons que le but du contrôleur devient un peu plus clair. Son travail consiste simplement à traduire les commandes sur le modèle et le résultat sur les vues. Cela se fait généralement sous la forme de ViewModels qui sont différents mais souvent confondus avec le modèle dans MVC.

Si vous n'avez pas de modèle bien défini, vous avez peut-être atteint le point où la majeure partie de cette logique réside maintenant dans les contrôleurs eux-mêmes. À ce stade, afin de commencer à réduire la taille de vos contrôleurs, vous pouvez commencer à récupérer cette logique dans des objets de gestionnaire ou de service. Ces services retournent et fonctionnent généralement sur des objets de type DTO / Entity. Ensuite, le contrôleur devient la couche de mappage entre ces services et les modèles de vue. Pour quelques bons conseils sur la cartographie, consultez cet article. Les amis ne laissent pas les amis utiliser AutoMapper .

Quant à vos questions, la première dépend beaucoup de vos applications. Vous devrez effectuer une refactorisation en cours de route, ce qui devrait devenir plus apparent une fois que vous aurez supprimé la logique de vos contrôleurs. En ce qui concerne les tests, il n'y a aucun problème à instancier des modèles dans les services, mais si vous trouvez que les tests sont difficiles, c'est probablement juste un signe que vous devez diviser le service en parties plus petites, chacune avec une seule responsabilité.


3

Les contrôleurs ne doivent contenir que des appels au modèle (là où la logique métier se produit) et sur la base de ces appels affecter des données pour la vue (objets d'informations ou messages d'erreur) donc les contrôleurs seront assez petits même pour une page très complexe, si le contrôleur continue devient très gros, vous devriez penser que peut-être cette page devrait être développée en plusieurs pages.

Pourtant, le modèle peut être assez gros ... la solution que j'ai trouvée était d'avoir une variable à l'intérieur du contrôleur qui indique quel modèle à charger et pour des tâches spécifiques, je charge le modèle spécifique.

Essayez d'obéir au modèle modèle-vue-contrôleur propre comme ceci:

  • vue: affiche les données
  • contrôleur: collecte les entrées utilisateur, demande au modèle les données demandées et les renvoie à la vue
  • modèle: interagit avec la base de données et effectue des actions logiques pour préparer les informations

-1

Je trouve les services vraiment utiles pour exécuter une logique qui peut devoir être exécutée par plusieurs contrôleurs ou qui n'est tout simplement pas suffisamment spécifique pour faire partie du contrôleur, outre le fait que cela empêche mes contrôleurs de devenir trop gros et difficiles à lire. .

Personnellement, je ne suis pas d'accord avec 'aaa' quand il dit que "modèle (où la logique commerciale se produit)", car c'est la raison pour laquelle vous avez des contrôleurs, à mon avis, les modèles doivent être de simples abstraits de données afin que le contrôleur puisse effectuer la tâche nécessaire; encore une fois, les services ne devraient pas s'impliquer dans la tâche d'abstraction des données ...

dire juste yo ....


1
Si votre modèle n'est qu'un dto, vous êtes tombé dans le modèle de domaine anémique antipattern martinfowler.com/bliki/AnemicDomainModel.html
Andy
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.