[GO] Modèles de conception à utiliser avec les bibliothèques Java fréquemment utilisées - Modèle de méthode de modèle

Les modèles de conception GoF sont également masqués dans les bibliothèques Java que vous utilisez le plus souvent. Il est facile d'oublier le travail quotidien chargé, mais de temps en temps, profitons du beau design qui peut être considéré comme une sorte d'art.

Cet art

fichier source

Classe HelloServlet


import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
...

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
            out.println("<html>");
            out.println("<body>");
            out.println("<h1>Hello, world!</h1>");
            out.println("</body>");
            out.println("</html>");
        }
    }
}

Résultat d'exécution

HelloWorld.png

Un programme Java Servlet Hello World que toute personne ayant utilisé Java côté serveur peut l'avoir vu une fois. Si vous la regardez à nouveau, vous serez submergé par le code source qui insiste fortement sur l'orientation de l'objet depuis le début.

Points d'appréciation

Avec Java Servlet, vous pouvez répondre aux requêtes HTTP GET simplement en héritant de la classe HttpServlet et en remplaçant la méthode doGet. (Le fichier XML doit avoir une description qui mappe la classe à l'URL.)

Le code ci-dessus semble être organisé de manière concise pour le code qui renvoie une réponse HTTP sans utiliser le framework WEB. Il semble y avoir un secret dans l'héritage de classe et le remplacement de méthode, mais quelle est la conception? Explorons ensemble.

Lorsque vous n'utilisez pas le modèle de méthode de modèle

Le code au début utilise le modèle de méthode modèle. Tout d'abord, réfléchissons à ce qui se passerait si nous n'utilisions pas le modèle de méthode modèle.

Dans Java Servlet, lorsqu'il y a une requête HTTP, la méthode service de la classe qui implémente l'interface Servlet correspondant à l'URL est appelée. Par conséquent, si vous implémentez la méthode service de l'interface Servlet dans votre propre classe qui n'a pas de classe parent comme indiqué ci-dessous, cela fonctionnera sans problème.

Classe HelloServlet


...
public class HelloServlet implements Servlet {
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request =  (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        //Traitement séparé par méthode de demande
        String method = request.getMethod();
        if (method.equals(METHOD_GET)) {
            //Le processus est divisé selon que l'en-tête de la date et de l'heure de la dernière mise à jour est ajouté.
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                //Lorsque l'en-tête de la date et de l'heure de la dernière mise à jour n'est pas ajouté
                //Créer du HTML
                response.setContentType("text/html;charset=UTF-8");
                try (PrintWriter out = response.getWriter()) {
                    out.println("<html>");
                    out.println("<body>");
                    out.println("<h1>Hello, world!</h1>");
                    out.println("</body>");
                    out.println("</html>");
                }
            } else {
                //Quand la date et l'heure de la dernière mise à jour en-tête sont ajoutées
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    maybeSetLastModified(response, lastModified);

                    //Créer du HTML
                    response.setContentType("text/html;charset=UTF-8");
                    try (PrintWriter out = response.getWriter()) {
                        out.println("<html>");
                        out.println("<body>");
                        out.println("<h1>Hello, world!</h1>");
                        out.println("</body>");
                        out.println("</html>");
                    }
                } else {
                    //S'il n'y a pas de mise à jour depuis la dernière fois, seul le code d'état est renvoyé
                    response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
      ...

Pour enregistrer cette classe en tant que servlet, écrivez un mappage de nom de classe URL dans le fichier XML.

web/WEB-INF/web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
</web-app>

Ensuite, si vous accédez avec l'URL de «nom de domaine / bonjour», le service «HelloServlet #» ci-dessus sera appelé. Le résultat de l'exécution est le même que l'image du début.

Si la seule fonction de ce système est d'afficher "Hello, world!", L'implémentation ci-dessus est correcte, mais lorsque de nouvelles fonctions sont nécessaires, cela devient de plus en plus pénible. En guise de test, ajoutez une classe ByeServlet avec de nouvelles fonctionnalités.

Classe ByeServlet


...
public class ByeServlet implements Servlet {
  @Override
  public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
      HttpServletRequest request =  (HttpServletRequest) req;
      HttpServletResponse response = (HttpServletResponse) res;

      //Traitement séparé par méthode de demande
      String method = request.getMethod();
      if (method.equals(METHOD_GET)) {
          //Le processus est divisé selon que l'en-tête de la date et de l'heure de la dernière mise à jour est ajouté.
          long lastModified = getLastModified(req);
          if (lastModified == -1) {
              //Lorsque l'en-tête de la date et de l'heure de la dernière mise à jour n'est pas ajouté
              //Créer du HTML
              response.setContentType("text/html;charset=UTF-8");
              try (PrintWriter out = response.getWriter()) {
                  out.println("<html>");
                  out.println("<body>");
                  out.println("<h1>Bye, world!</h1>");
                  out.println("</body>");
                  out.println("</html>");
              }
          } else {
              //Quand la date et l'heure de la dernière mise à jour en-tête sont ajoutées
              long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
              if (ifModifiedSince < lastModified) {
                  maybeSetLastModified(response, lastModified);

                  //Créer du HTML
                  response.setContentType("text/html;charset=UTF-8");
                  try (PrintWriter out = response.getWriter()) {
                      out.println("<html>");
                      out.println("<body>");
                      out.println("<h1>Bye, world!</h1>");
                      out.println("</body>");
                      out.println("</html>");
                  }
              } else {
                  //S'il n'y a pas de mise à jour depuis la dernière fois, seul le code d'état est renvoyé
                  response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
              }
          }

      } else if (method.equals(METHOD_HEAD)) {
      ...

web/WEB-INF/web.xml (montant supplémentaire)


...
  <!--Ajouts-->
  <servlet>
      <servlet-name>bye</servlet-name>
      <servlet-class>ByeServlet</servlet-class>
  </servlet>
  <servlet-mapping>
      <servlet-name>bye</servlet-name>
      <url-pattern>/bye</url-pattern>
  </servlet-mapping>
...

Si vous accédez avec l'URL de nom de domaine / bye, ByeServlet fonctionnera et le navigateur affichera ce qui suit.

ByeWorld.png

Comparons maintenant les deux servlets HelloServlet et ByeServlet. Le flux de traitement est ** les deux ** comme suit.

Flux de processus

  1. Traitement séparé par méthode de demande (GET / POST, etc.)
  2. Assurez-vous que le dernier en-tête de date et d'heure modifié est ajouté
  3. Renvoie du HTML s'il n'est pas accordé
  4. Renvoie le HTML s'il est accordé et mis à jour
  5. S'il est accordé et qu'il n'y a pas de mise à jour, seul le code d'état est renvoyé

La seule différence entre les deux classes est le contenu du "retour HTML", les autres sont exactement les mêmes. ** Bien que le flux de traitement soit le même, le code source est dupliqué et il semble qu'il a été copié et réutilisé **. C'est une mise en œuvre douloureuse et ce n'est pas beau.

Lors de l'utilisation du modèle de méthode de modèle

Maintenant, appliquons le modèle de méthode de modèle.

Le traitement commun entre les classes est implémenté dans la classe parente, et seul un traitement différent est implémenté dans la classe enfant. Dans cet exemple, le "traitement commun" consiste à diviser le flux en fonction de l'en-tête de la dernière date et heure de mise à jour, et "traitement différent" consiste à générer du HTML.

La première est la classe parente.

java:Implémentation de la classe parente (javax.servlet.http.Classe HttpServlet)


package javax.servlet.http;
...
public abstract class HttpServlet extends GenericServlet {
    ...
    /**
     *Méthodes à remplacer dans les classes enfants
     */
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //Puisqu'il est censé être remplacé dans la classe enfant, ce sera une erreur s'il passe ici
    }

    /**
     *Méthode de modèle
     */
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        if (method.equals(METHOD_GET)) {
            //Traitement des modifications selon que la date et l'heure de la dernière mise à jour sont ajoutées
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                //Lorsque l'en-tête de la date et de l'heure de la dernière mise à jour n'est pas ajouté
                //Créer du HTML
                doGet(req, resp);
            } else {
                //Quand la date et l'heure de la dernière mise à jour en-tête sont ajoutées
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    maybeSetLastModified(resp, lastModified);

                    //Créer du HTML
                    doGet(req, resp);
                } else {
                    //Renvoie uniquement le code d'état
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
        ...

Ce qui précède n'est pas le code que j'ai écrit, mais le code de la classe de servlet standard Java Servlet javax.servlet.http.HttpServlet tel quel. Lors de la création d'un Java Servlet, normalement, cette classe est héritée et la classe enfant implémente le traitement correspondant à la méthode de requête HTTP (GET / POST, etc.). Ce sera comme suit.

Implémentation de la classe enfant (classe HelloServlet)


...
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Créer du HTML
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
            out.println("<html>");
            out.println("<body>");
            out.println("<h1>Hello, world!</h1>");
            out.println("</body>");
            out.println("</html>");
        }
    }
}

Implémentation de la classe enfant (classe ByeServlet)


...
public class ByeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Créer du HTML
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
            out.println("<html>");
            out.println("<body>");
            out.println("<h1>Bye, world!</h1>");
            out.println("</body>");
            out.println("</html>");
        }
    }
}

De cette façon, en regroupant les processus communs entre les classes dans une classe parente (HttpServlet) et en décrivant les différents processus dans les méthodes ( doGet) de chaque classe enfant, ** il n'y a pas de duplication du code source. C'était **. De plus, lors de l'ajout d'une nouvelle fonction (serviteur), il suffit d'hériter de la classe parent et d'implémenter une méthode, ainsi ** n'importe qui peut facilement l'implémenter **. Comparé à avant d'appliquer le motif, il est magnifique.

La définition du GoF du modèle de méthode de modèle est "** Définir le squelette de l'algorithme dans une certaine opération, laisser la définition de certains traitements à la sous-classe, et elle est incluse dans celle-ci sans changer la structure de l'algorithme. C'est [^ 1] ** "pour redéfinir le processus. La "structure de l'algorithme" correspond ici à la logique effectuée dans la classe parente, qui divise le traitement par la méthode HTTP, divise le traitement en fonction de l'en-tête de la date et de l'heure de la dernière mise à jour, et renvoie le code HTML et statut. De plus, «redéfinir le processus» correspond à la partie qui renvoie du HTML, ce qui est fait dans la classe enfant.

Commentaires d'experts sur le modèle de méthode modèle

De nombreux experts ont également commenté l'évaluation du modèle de méthode modèle.

lang_and_engine

Quel est le but de la création de classes abstraites en langage Java? Si vous apprenez de ce point, vous pouvez accepter ce modèle sans aucune résistance.

De Liste de 23 modèles de conception GoF à utiliser en Java

Hiroshi Yuki

L'algorithme étant décrit par la méthode template de la super classe, il n'est pas nécessaire de décrire l'algorithme un par un côté sous-classe.

["Introduction aux modèles de conception appris en langage Java"](https://www.amazon.co.jp/ Introduction aux modèles de conception appris en langage Java-Yuki-Hiroshi / dp / 4797327030 /)

finalement

C'est un plaisir pour les programmeurs de pouvoir profiter du plaisir intellectuel en regardant simplement quelques lignes de code sans avoir à se rendre au musée.

Si vous êtes un ingénieur qui sympathise avec l'art du modèle de méthode de modèle, veuillez contacter le personnel de recrutement de notre société (Qualysite Technologies Co., Ltd.). Merci de bien vouloir me contacter!

Article associé

Créer une instance

Simplifiez l'interface

Laissez-le à une autre classe

URL de référence

[^ 1]: ["Modèle de conception à réutiliser dans l'orientation objet"](https://www.amazon.co.jp/%E3%82%AA%E3%83%96%E3%82%B8 % E3% 82% A7% E3% 82% AF% E3% 83% 88% E6% 8C% 87% E5% 90% 91% E3% 81% AB% E3% 81% 8A% E3% 81% 91% E3 % 82% 8B% E5% 86% 8D% E5% 88% A9% E7% 94% A8% E3% 81% AE% E3% 81% 9F% E3% 82% 81% E3% 81% AE% E3% 83 % 87% E3% 82% B6% E3% 82% A4% E3% 83% B3% E3% 83% 91% E3% 82% BF% E3% 83% BC% E3% 83% B3-% E3% 82% AC% E3% 83% B3% E3% 83% 9E-% E3% 82% A8% E3% 83% AA% E3% 83% 83% E3% 82% AF / dp / 479731126 / ref = sr_1_1? Ie = UTF8 & qid = 1495503419 & sr = 8-1 & mots-clés =% E3% 82% AA% E3% 83% 96% E3% 82% B8% E3% 82% A7% E3% 82% AF% E3% 83% 88% E6% 8C% 87% E5% 90% 91% E3% 81% AB% E3% 81% 8A% E3% 81% 91% E3% 82% 8B% E5% 86% 8D% E5% 88% A9% E7% 94% A8% E3% 81% AE% E3% 81% 9F% E3% 82% 81% E3% 81% AE% E3% 83% 87% E3% 82% B6% E3% 82% A4% E3% 83% B3% E3% 83% À partir de 91% E3% 82% BF% E3% 83% BC% E3% 83% B3)

Recommended Posts

Modèles de conception à utiliser avec les bibliothèques Java fréquemment utilisées - Modèle de méthode de modèle
Modèles de conception à utiliser avec les bibliothèques Java fréquemment utilisées - Modèles d'adaptateur
Modèles de conception à utiliser avec les bibliothèques Java fréquemment utilisées - Modèles de stratégie
Modèles de conception à utiliser avec les bibliothèques Java fréquemment utilisées - Modèle de façade
Modèles de conception appris avec Java et PHP (résumé)
Modèles de conception à utiliser avec les bibliothèques Java fréquemment utilisées - Modèles d'adaptateur
Modèles de conception à utiliser avec les bibliothèques Java fréquemment utilisées - Modèles de stratégie
Modèles de conception à utiliser avec les bibliothèques Java fréquemment utilisées - Modèle de méthode de modèle
Modèles de conception à utiliser avec les bibliothèques Java fréquemment utilisées - Modèle de façade
Modèles de conception à utiliser avec les bibliothèques Java fréquemment utilisées - Modèle abstrait Factory
Modèles de conception appris avec Java et PHP (résumé)
Docker. Définir les commandes fréquemment utilisées sur un alias "avec explication"
[Mis à jour de temps en temps] Résumé des modèles de conception en Java
Résumé du chapitre 2 de l'introduction aux modèles de conception appris en langage Java
Chapitre 4 Résumé de l'introduction aux modèles de conception appris en langage Java
Résumé du chapitre 3 de l'introduction aux modèles de conception appris en langage Java
Docker. Définir les commandes fréquemment utilisées sur un alias "avec explication"
Design Pattern #Template, méthode
[Mis à jour de temps en temps] Résumé des modèles de conception en Java
Modèle de méthode de modèle en Java
Python Design Pattern - Méthode de modèle
Résumé du chapitre 2 de l'introduction aux modèles de conception appris en langage Java
Chapitre 4 Résumé de l'introduction aux modèles de conception appris en langage Java
Résumé du chapitre 3 de l'introduction aux modèles de conception appris en langage Java
J'ai essayé de résumer la méthode de mise en œuvre fréquemment utilisée de pytest-mock