GoF-Entwurfsmuster sind auch in den Java-Bibliotheken versteckt, die Sie am häufigsten verwenden. Es ist leicht, die geschäftige tägliche Arbeit zu übersehen, aber ab und zu genießen wir das schöne Design, das man als eine Art Kunst bezeichnen kann.
HelloServlet-Klasse
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>");
}
}
}
Ein Java Servlet Hello World-Programm, das jeder, der Java auf der Serverseite verwendet hat, möglicherweise einmal gesehen hat. Wenn Sie es sich noch einmal ansehen, werden Sie von dem Quellcode überwältigt sein, der von Anfang an stark auf Objektorientierung besteht.
Java Servlet kann HTTP-GET-Anforderungen verarbeiten, indem es einfach die Klasse "HttpServlet" erbt und die Methode "doGet" überschreibt. (Die XML-Datei muss eine Beschreibung enthalten, die die Klasse der URL zuordnet.)
Der obige Code scheint für Code, der eine HTTP-Antwort ohne Verwendung des WEB-Frameworks zurückgibt, übersichtlich organisiert zu sein. Es scheint ein Geheimnis in der Klassenvererbung und der Methodenüberschreibung zu geben, aber wie sieht das Design aus? Lassen Sie uns gemeinsam erkunden.
Der Code am Anfang verwendet das Muster der Vorlagenmethode. Lassen Sie uns zunächst überlegen, was passieren würde, wenn wir das Muster der Vorlagenmethode nicht verwenden würden.
Wenn in Java Servlet eine HTTP-Anforderung vorliegt, wird die "service" -Methode der Klasse aufgerufen, die die der URL entsprechende "Servlet" -Schnittstelle implementiert. Wenn Sie die "service" -Methode der "Servlet" -Schnittstelle in Ihrer eigenen Klasse implementieren, die keine übergeordnete Klasse hat, wie unten gezeigt, funktioniert dies daher problemlos.
HelloServlet-Klasse
...
public class HelloServlet implements Servlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//Separate Verarbeitung nach Anforderungsmethode
String method = request.getMethod();
if (method.equals(METHOD_GET)) {
//Der Prozess wird danach aufgeteilt, ob der Header für das Datum und die Uhrzeit der letzten Aktualisierung hinzugefügt wurde.
long lastModified = getLastModified(req);
if (lastModified == -1) {
//Wenn der Header für das Datum und die Uhrzeit der letzten Aktualisierung nicht hinzugefügt wird
//Erstellen Sie 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 {
//Wenn der Header für das Datum und die Uhrzeit der letzten Aktualisierung hinzugefügt wird
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
maybeSetLastModified(response, lastModified);
//Erstellen Sie 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 {
//Wenn es beim letzten Mal keine Aktualisierung gibt, wird nur der Statuscode zurückgegeben
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
...
Um diese Klasse als Servlet zu registrieren, schreiben Sie eine Namenszuordnung für URL-Klassen in die XML-Datei.
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>
Wenn Sie dann mit der URL "Domain Name / Hallo" zugreifen, wird der oben genannte "HelloServlet # Service" aufgerufen. Das Ausführungsergebnis ist das gleiche wie das Bild am Anfang.
Wenn die Funktion dieses Systems nur darin besteht, "Hallo Welt!" Anzuzeigen, ist die obige Implementierung in Ordnung, aber wenn neue Funktionen benötigt werden, wird es immer schmerzhafter. Fügen Sie als Test eine ByeServlet-Klasse mit neuen Funktionen hinzu.
ByeServlet-Klasse
...
public class ByeServlet implements Servlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//Separate Verarbeitung nach Anforderungsmethode
String method = request.getMethod();
if (method.equals(METHOD_GET)) {
//Der Prozess wird danach aufgeteilt, ob der Header für das Datum und die Uhrzeit der letzten Aktualisierung hinzugefügt wurde.
long lastModified = getLastModified(req);
if (lastModified == -1) {
//Wenn der Header für das Datum und die Uhrzeit der letzten Aktualisierung nicht hinzugefügt wird
//Erstellen Sie 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 {
//Wenn der Header für das Datum und die Uhrzeit der letzten Aktualisierung hinzugefügt wird
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
maybeSetLastModified(response, lastModified);
//Erstellen Sie 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 {
//Wenn es beim letzten Mal keine Aktualisierung gibt, wird nur der Statuscode zurückgegeben
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
...
web/WEB-INF/web.xml (zusätzliche Menge)
...
<!--Ergänzungen-->
<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>
...
Wenn Sie mit der URL "Domain Name / Bye" zugreifen, funktioniert "ByeServlet" und der Browser zeigt Folgendes an.
Vergleichen wir nun die beiden Servlets "HelloServlet" und "ByeServlet". Der Verarbeitungsablauf ist ** beide ** wie folgt.
Prozessablauf
Der einzige Unterschied zwischen den beiden Klassen ist der Inhalt von "HTML zurückgeben", die anderen sind genau gleich. ** Obwohl der Verarbeitungsablauf derselbe ist, wird der Quellcode dupliziert und es sieht so aus, als ob er kopiert und wiederverwendet wurde **. Es ist eine schmerzhafte Implementierung und nicht schön.
Wenden wir nun das Muster der Vorlagenmethode an.
Die gemeinsame Verarbeitung zwischen Klassen ist in der übergeordneten Klasse implementiert, und in der untergeordneten Klasse ist nur eine andere Verarbeitung implementiert. In diesem Beispiel besteht "gemeinsame Verarbeitung" darin, den Fluss nach dem Header des Datums und der Uhrzeit der letzten Aktualisierung zu teilen, und "unterschiedliche Verarbeitung" besteht darin, HTML zu generieren.
Erstens ist die Elternklasse.
java:Implementierung der übergeordneten Klasse (javax.servlet.http.HttpServlet-Klasse)
package javax.servlet.http;
...
public abstract class HttpServlet extends GenericServlet {
...
/**
*Methoden zum Überschreiben in untergeordneten Klassen
*/
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//Da es in der untergeordneten Klasse überschrieben werden soll, ist es ein Fehler, wenn es hier bestanden wird
}
/**
*Vorlagenmethode
*/
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
//Die Verarbeitung ändert sich abhängig davon, ob der Header für das Datum und die Uhrzeit der letzten Aktualisierung hinzugefügt wurde
long lastModified = getLastModified(req);
if (lastModified == -1) {
//Wenn der Header für das Datum und die Uhrzeit der letzten Aktualisierung nicht hinzugefügt wird
//Erstellen Sie HTML
doGet(req, resp);
} else {
//Wenn der Header für das Datum und die Uhrzeit der letzten Aktualisierung hinzugefügt wird
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
maybeSetLastModified(resp, lastModified);
//Erstellen Sie HTML
doGet(req, resp);
} else {
//Gibt nur den Statuscode zurück
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
...
Das Obige ist nicht der Code, den ich geschrieben habe, sondern der Code der Java-Servlet-Standard-Servlet-Klasse javax.servlet.http.HttpServlet
wie er ist. Beim Erstellen eines Java-Servlets wird diese Klasse normalerweise vererbt und die untergeordnete Klasse implementiert die Verarbeitung entsprechend der HTTP-Anforderungsmethode (GET / POST usw.). Es wird wie folgt sein.
Implementierung einer untergeordneten Klasse (HelloServlet-Klasse)
...
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Erstellen Sie 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>");
}
}
}
Implementierung einer untergeordneten Klasse (ByeServlet-Klasse)
...
public class ByeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Erstellen Sie 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>");
}
}
}
Auf diese Weise wird durch Gruppieren gemeinsamer Prozesse zwischen Klassen in einer übergeordneten Klasse (HttpServlet
) und Beschreiben verschiedener Prozesse in den Methoden ( doGet
) jeder untergeordneten Klasse ** keine Duplizierung des Quellcodes vorgenommen. Es war **. Wenn Sie eine neue Funktion (Servant) hinzufügen, müssen Sie nur die übergeordnete Klasse erben und eine Methode implementieren, damit ** jeder sie problemlos implementieren kann **. Im Vergleich zu vor dem Auftragen des Musters sieht es wunderschön aus.
Die GoF-Definition des Template-Methodenmusters lautet "** Definieren Sie das Grundgerüst des Algorithmus in einer Operation und überlassen Sie die Definition einer Verarbeitung der Unterklasse. Sie ist darin enthalten, ohne die Struktur des Algorithmus zu ändern. Es ist [^ 1] ** ", den Prozess neu zu definieren. Die "Algorithmusstruktur" entspricht hier der in der übergeordneten Klasse ausgeführten Logik, die die Verarbeitung durch die HTTP-Methode teilt, die Verarbeitung nach dem Header des Datums und der Uhrzeit der letzten Aktualisierung unterteilt und HTML und den Statuscode zurückgibt. Außerdem entspricht "Neudefinition des Prozesses" dem Teil, der HTML zurückgibt, was in der untergeordneten Klasse erfolgt.
Viele Experten haben sich auch zur Bewertung des Musters der Vorlagenmethode geäußert.
lang_and_engine
Was ist der Zweck der Erstellung abstrakter Klassen in der Java-Sprache? Wenn Sie von diesem Punkt lernen, können Sie dieses Muster ohne Widerstand akzeptieren.
Hiroshi Yuki
Da der Algorithmus durch die Template-Methode der Superklasse beschrieben wird, ist es nicht erforderlich, den Algorithmus einzeln auf der Unterklassenseite zu beschreiben.
["Einführung in in Java-Sprache erlernte Entwurfsmuster"](https://www.amazon.co.jp/ Einführung in in Java-Sprache erlernte Entwurfsmuster-Yuki-Hiroshi / dp / 4797327030 /)
Es ist eine Freude für Programmierer, intellektuellen Genuss zu genießen, indem sie nur ein paar Codezeilen betrachten, ohne ins Museum gehen zu müssen.
Wenn Sie ein Ingenieur sind, der mit der Kunst des Template-Methodenmusters einverstanden ist, wenden Sie sich bitte an den Einstellungsmanager unseres Unternehmens (Qualysite Technologies Co., Ltd.). Bitte kontaktiere mich!
[^ 1]: ["Entwurfsmuster für die Wiederverwendung in der Objektorientierung"](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 & keywords =% 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% Von 91% E3% 82% BF% E3% 83% BC% E3% 83% B3)
Recommended Posts