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.
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>");
}
}
}
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.
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.
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.
Comparons maintenant les deux servlets HelloServlet
et ByeServlet
. Le flux de traitement est ** les deux ** comme suit.
Flux de processus
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.
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.
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.
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 /)
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!
[^ 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