8 votes

Différence entre la couche de service et le contrôleur en pratique

J'ai lu de nombreuses théories sur les différences entre la couche de service et le contrôleur, et j'ai quelques questions sur la manière de réaliser cela en pratique. Une réponse à Couche de service et contrôleur : qui gère quoi ? dit:

J'essaie de limiter les contrôleurs à effectuer des tâches liées à la validation des paramètres http, à décider quelle méthode de service appeler avec quels paramètres, à mettre dans la session https ou la requête, à rediriger vers quelle vue, ou à effectuer des tâches similaires liées au web.

et de http://www.bennadel.com/blog/2379-a-better-understanding-of-mvc-model-view-controller-thanks-to-steven-neiland.htm :

Drapeaux rouges : Mon architecture de contrôleur pourrait ne pas être bonne si :

Le contrôleur effectue trop de requêtes à la couche de service. Le contrôleur effectue un certain nombre de requêtes à la couche de service qui ne renvoient pas de données. Le contrôleur effectue des requêtes à la couche de service sans passer d'arguments.

En ce moment, je développe une application web avec Spring MVC, et j'ai cette méthode pour enregistrer l'e-mail modifié de l'utilisateur:

/**
     * 

Vous pouvez voir que j'ai beaucoup de requêtes à la couche de service, et je fais des redirections depuis le contrôleur - c'est de la logique métier. Veuillez montrer une meilleure version de cette méthode.

Et un autre exemple. J'ai cette méthode, qui renvoie le profil de l'utilisateur:

/**
     * Retourne {@link ModelAndView} le profil du client
     * @param user - le principal, à partir duquel nous obtenons {@code Client}
     * @throws UnsupportedEncodingException
     */
    @RequestMapping(value = "/profile", method = RequestMethod.GET)
    public ModelAndView profile(Principal user) throws UnsupportedEncodingException{
        Client clientFromDB = (Client)clientService.getUserByEmail(user.getName());
        ModelAndView model = new ModelAndView("/client/profile");
        model.addObject("client", clientFromDB);
        if(clientFromDB.getAvatar() != null){
            model.addObject("image", convertAvaForRendering(clientFromDB.getAvatar()));
        }
        return model;
    }

La méthode convertAvaForRendering(clientFromDB.getAvatar()) est placée dans la super-classe de ce contrôleur, c'est un bon endroit pour cette méthode, ou doit-elle être placée dans la couche de service ?

Aidez s'il vous plaît, c'est vraiment important pour moi.

10voto

Arthur Noseda Points 1541

Un Controller Spring est généralement lié à l'API Spring (avec des classes comme Model, ModelAndView...) ou à l'API Servlet (HttpServletRequest, HttpServletResponse...). Les méthodes peuvent renvoyer des résultats de type String qui seront résolus en tant que nom de template (JSP...). Les Controller sont très probablement orientés vers les interfaces graphiques Web, avec une forte dépendance à la technologie Web.

Les Services, quant à eux, devraient être conçus en ayant à l'esprit la logique métier et sans aucune hypothèse sur le client. Nous pourrions rendre le service distant, l'exposer en tant que service Web, mettre en place une interface Web, ou un client Swing. Un Service ne devrait pas dépendre de Spring MVC, de l'API Servlet, et autres. De cette manière, si vous avez besoin de retargeter votre application, vous pourriez réutiliser la majeure partie de la logique métier.

En ce qui concerne la remarque concernant trop d'appels à la couche de service depuis la couche de contrôle, il s'agit principalement d'une question de performances, qui à mon avis est quelque chose de différent. Si chaque appel à la couche de service interroge une base de données, vous pourriez rencontrer des problèmes de performances. Si la couche de service et la couche de contrôle ne s'exécutent pas dans le même JVM, vous pourriez également rencontrer des problèmes de performances. Il s'agit là d'un autre aspect très important de la conception de votre application, mais cela indiquerait que vous devriez créer des façades pour vos appels de services afin de fournir des opérations plus grossières à la couche de contrôle.

7voto

Andreas Points 3334

Dans les deux exemples, pourquoi avez-vous besoin de caster Client? C'est une mauvaise pratique de code.

Puisque l'appel à la couche de service est également l'appel qui établit la frontière de la transaction de la base de données, faire plusieurs appels signifie qu'ils sont exécutés dans des transactions différentes et ne sont donc pas nécessairement cohérents entre eux.

C'est l'une des raisons pour lesquelles les appels multiples sont déconseillés. @ArthurNoseda mentionne une autre bonne raison dans sa réponse.

Dans votre premier cas, il devrait y avoir un seul appel à la couche de service, par exemple quelque chose comme ceci:

if (changeEmailResult.hasErrors()) {
    return new ModelAndView("/client/editEmail");
}
try {
    clientService.updateUserEmail(user.getName(),
                                  changeEmailBean.getCurrentPassword(),
                                  changeEmailBean.getNewEmail());
} catch (InvalidPasswordException unused) {
    ModelAndView model = new ModelAndView("/client/editEmail");
    model.addObject("wrongPassword", "Le mot de passe ne correspond pas réellement");
    return model;
} catch (DuplicateEmailException unused) {
    ModelAndView model = new ModelAndView("/client/editEmail");
    model.addObject("email", oldEmail);
    model.addObject("emailExists", "Un tel e-mail est déjà enregistré dans le système");
    return model;
}
refreshUsername(newEmail);
return new ModelAndView("redirect:/client/profile");

Vous pourriez également utiliser la valeur de retour au lieu des exceptions.

Comme vous pouvez le voir, cela déléguera la logique métier du changement d'e-mail à la couche de service, tout en conservant toutes les actions liées à l'interface utilisateur dans le contrôleur où elles appartiennent.

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