Ich entwerfe eine einfache webbasierte Anwendung. Ich bin neu in dieser webbasierten Domain. Ich brauchte Ihren Rat bezüglich der Entwurfsmuster wie der Verteilung der Verantwortung auf Servlets, der Kriterien für die Erstellung eines neuen Servlets usw.
Tatsächlich habe ich nur wenige Entitäten auf meiner Homepage und entsprechend jeder von ihnen haben wir einige Optionen wie Hinzufügen, Bearbeiten und Löschen. Früher habe ich ein Servlet pro Option verwendet, z. B. Servlet1 zum Hinzufügen von Entity1, Servlet2 zum Bearbeiten von Entity1 usw. Auf diese Weise hatten wir eine große Anzahl von Servlets.
Jetzt ändern wir unser Design. Meine Frage ist, wie Sie genau auswählen, wie Sie die Verantwortung für ein Servlet auswählen. Sollten wir ein Servlet pro Entität haben, das alle Optionen verarbeitet und die Anforderung an die Serviceschicht weiterleitet. Oder sollten wir ein Servlet für die gesamte Seite haben, das die gesamte Seitenanforderung verarbeitet und dann an die entsprechende Serviceschicht weiterleitet? Sollte das Anforderungsobjekt an die Serviceschicht weitergeleitet werden oder nicht?
quelle
Antworten:
Eine etwas anständige Webanwendung besteht aus einer Mischung von Designmustern. Ich werde nur die wichtigsten erwähnen.
Model View Controller-Muster
Das zentrale (architektonische) Entwurfsmuster, das Sie verwenden möchten, ist das Model-View-Controller-Muster . Der Controller soll durch ein Servlet dargestellt werden, das (in) direkt ein bestimmtes Modell und eine bestimmte Ansicht basierend auf der Anforderung erstellt / verwendet . Das Modell soll durch javabäische Klassen dargestellt werden. Dies ist im Geschäftsmodell, das die Aktionen (Verhalten) enthält, und im Datenmodell, das die Daten (Informationen) enthält, häufig weiter teilbar . Die Ansicht soll durch JSP-Dateien dargestellt werden, die über EL (Expression Language) direkten Zugriff auf das ( Daten- ) Modell haben .
Dann gibt es Variationen, die darauf basieren, wie Aktionen und Ereignisse behandelt werden. Die beliebtesten sind:
Anforderungs- (Aktions-) MVC : Dies ist am einfachsten zu implementieren. Das ( Geschäfts- ) Modell arbeitet direkt mit
HttpServletRequest
undHttpServletResponse
Objekten. Sie müssen die Anforderungsparameter (meistens) selbst erfassen, konvertieren und validieren. Die Ansicht kann durch einfaches Vanille-HTML / CSS / JS dargestellt werden und behält den Status nicht über Anforderungen hinweg bei. So funktioniert unter anderem Spring MVC , Struts and Stripes .Komponentenbasierte MVC : Dies ist schwieriger zu implementieren. Am Ende erhalten Sie jedoch ein einfacheres Modell und eine einfachere Ansicht, in der die gesamte "rohe" Servlet-API vollständig entfernt wird. Sie sollten die Anforderungsparameter nicht selbst erfassen, konvertieren und validieren müssen. Der Controller führt diese Aufgabe aus und legt die gesammelten, konvertierten und validierten Anforderungsparameter im Modell fest . Sie müssen lediglich Aktionsmethoden definieren, die direkt mit den Modelleigenschaften funktionieren. Die Ansicht wird durch "Komponenten" in der Variante von JSP-Taglibs oder XML-Elementen dargestellt, die wiederum HTML / CSS / JS generieren. Der Status der Ansichtfür die nachfolgenden Anfragen wird in der Sitzung gepflegt. Dies ist besonders hilfreich für serverseitige Konvertierungs-, Validierungs- und Wertänderungsereignisse. So geht unter anderem JSF , Wicket and Play! funktioniert.
Nebenbei bemerkt, das Hobby mit einem selbstgebauten MVC-Framework ist eine sehr schöne Lernübung, und ich empfehle es, solange Sie es für persönliche / private Zwecke aufbewahren. Wenn Sie jedoch erst einmal professionell sind, wird dringend empfohlen, ein vorhandenes Framework auszuwählen, anstatt Ihr eigenes neu zu erfinden. Das Erlernen eines vorhandenen und gut entwickelten Frameworks dauert langfristig weniger lange als das Entwickeln und Verwalten eines robusten Frameworks.
In der folgenden detaillierten Erklärung beschränke ich mich auf anforderungsbasierte MVC, da dies einfacher zu implementieren ist.
Front Controller-Muster ( Mediator-Muster )
Zunächst sollte der Controller- Teil das Front-Controller-Muster implementieren (eine spezielle Art von Mediator-Muster ). Es sollte nur aus einem einzigen Servlet bestehen, das einen zentralen Einstiegspunkt für alle Anforderungen bietet. Das Modell sollte auf der Grundlage der von der Anforderung verfügbaren Informationen erstellt werden, z. B. der Pfadinfo oder des Servletpfads, der Methode und / oder bestimmter Parameter. Das Geschäftsmodell wird
Action
im folgendenHttpServlet
Beispiel aufgerufen .Das Ausführen der Aktion sollte eine Kennung zurückgeben, um die Ansicht zu lokalisieren. Am einfachsten wäre es, es als Dateinamen der JSP zu verwenden. Karte Servlet auf einem bestimmten
url-pattern
inweb.xml
, zum Beispiel/pages/*
,*.do
oder auch nur*.html
.Im Fall von Präfix-Muster , wie zum Beispiel
/pages/*
könnten Sie dann invoke URL ist wie http://example.com/pages/register , http://example.com/pages/login , etc. und bietet/WEB-INF/register.jsp
,/WEB-INF/login.jsp
mit der entsprechenden GET und POST - Aktionen . Die Teileregister
,login
sind etc dann zur Verfügung ,request.getPathInfo()
wie in obigem Beispiel.Wenn Sie mit Suffix-Muster wie
*.do
,*.html
etc, dann könnte man dann invoke URL wie http://example.com/register.do , http://example.com/login.do , etc , und Sie sollten das ändern Codebeispiele in dieser Antwort (auch dieActionFactory
), um stattdessen dieregister
undlogin
Teile zu extrahierenrequest.getServletPath()
.Strategiemuster
Die
Action
sollten dem Strategiemuster folgen . Es muss als abstrakter / Schnittstellentyp definiert werden, der die Arbeit basierend auf den übergebenen Argumenten der abstrakten Methode ausführen soll (dies ist der Unterschied zum Befehlsmuster , wobei der abstrakte / Schnittstellentyp die Arbeit basierend auf dem ausführen soll Argumente, die bei der Erstellung der Implementierung übergeben wurden).Möglicherweise möchten Sie die
Exception
mit einer benutzerdefinierten Ausnahme wie präzisierenActionException
. Es ist nur ein einfaches Kickoff-Beispiel, der Rest liegt ganz bei Ihnen.Hier ist ein Beispiel für ein,
LoginAction
das (wie der Name schon sagt) den Benutzer anmeldet. DasUser
selbst ist wiederum ein Datenmodell . Die Ansicht ist sich der Anwesenheit der bewusstUser
.Fabrikmethodenmuster
Das
ActionFactory
sollte dem Factory-Methodenmuster folgen . Grundsätzlich sollte eine Erstellungsmethode bereitgestellt werden, die eine konkrete Implementierung eines Abstract- / Interface-Typs zurückgibt. In diesem Fall sollte eine Implementierung derAction
Schnittstelle basierend auf den von der Anforderung bereitgestellten Informationen zurückgegeben werden. Beispiel: Methode und Pfadinfo (die Pfadinfo ist der Teil nach dem Kontext und dem Servlet-Pfad in der Anforderungs-URL, ausgenommen die Abfragezeichenfolge).Die
actions
wiederum sollte statisch / anwendungsweit seinMap<String, Action>
und alle bekannten Aktionen enthalten. Es liegt an Ihnen, wie Sie diese Karte füllen. Hardcodierung:Oder konfigurierbar basierend auf einer Eigenschaften- / XML-Konfigurationsdatei im Klassenpfad: (Pseudo)
Oder dynamisch basierend auf einem Scan im Klassenpfad nach Klassen, die eine bestimmte Schnittstelle und / oder Anmerkung implementieren: (Pseudo)
Denken Sie daran, ein "Nichts tun"
Action
für den Fall zu erstellen, dass keine Zuordnung vorliegt. Lassen Sie es zum Beispiel direkt dasrequest.getPathInfo().substring(1)
Dann zurückgeben.Andere Muster
Das waren bisher die wichtigen Muster.
Um noch einen Schritt weiter zu kommen, können Sie das Facade-Muster verwenden , um eine
Context
Klasse zu erstellen , die wiederum die Anforderungs- und Antwortobjekte umschließt und verschiedene praktische Methoden bietet, die an die Anforderungs- und Antwortobjekte delegieren und dieseAction#execute()
stattdessen als Argument an die Methode übergeben. Dadurch wird eine zusätzliche abstrakte Ebene hinzugefügt, um die unformatierte Servlet-API auszublenden. Sie sollten dann grundsätzlich in jeder Implementierung keineimport javax.servlet.*
Deklarationen habenAction
. In JSF-Begriffen ist dies das, was die KlassenFacesContext
undExternalContext
tun. In dieser Antwort finden Sie ein konkretes Beispiel .Dann gibt es das Statusmuster für den Fall, dass Sie eine zusätzliche Abstraktionsschicht hinzufügen möchten, um die Aufgaben des Sammelns der Anforderungsparameter, Konvertieren, Validieren, Aktualisieren der Modellwerte und Ausführen der Aktionen aufzuteilen. In JSF-Begriffen ist dies das, was der
LifeCycle
tut.Dann gibt es das zusammengesetzte Muster für den Fall, dass Sie eine komponentenbasierte Ansicht erstellen möchten, die an das Modell angehängt werden kann und deren Verhalten vom Status des anforderungsbasierten Lebenszyklus abhängt. In JSF-Begriffen ist dies das, was die
UIComponent
darstellen.Auf diese Weise können Sie sich Stück für Stück zu einem komponentenbasierten Framework entwickeln.
Siehe auch:
quelle
web.xml
, können Sie einServletContextListener
dafür verwenden. Lassen Sie es vom Werk implementieren (und registrieren Sie sich wie<listener>
inweb.xml
) und erledigen Sie den Füllvorgang während descontextInitialized()
Verfahrens.Action
Implementierung genauso wie bei normalen Servlets richtig zu machen (siehe auch Servlet-Wiki für ein grundlegendes Beispiel, das Sie weiter in eineValidator
Schnittstelle umgestalten können). Sie können dies jedoch auch vor dem Aufrufen der Aktion tun. Dies ist jedoch komplexer, da die Validierungsregeln pro Ansicht bekannt sein müssen. JSF ist dies durch das Angebot gedecktrequired="true"
,validator="customValidatorName"
usw. in dem XHTML - Markup.In dem verprügelten MVC-Muster ist das Servlet "C" - Controller.
Seine Hauptaufgabe besteht darin, eine erste Anforderungsbewertung durchzuführen und dann die Verarbeitung basierend auf der anfänglichen Bewertung an den spezifischen Mitarbeiter zu senden. Eine der Aufgaben des Arbeiters kann darin bestehen, einige Präsentations-Layer-Beans einzurichten und die Anforderung zum Rendern von HTML an die JSP-Seite weiterzuleiten. Allein aus diesem Grund müssen Sie das Anforderungsobjekt an die Serviceschicht übergeben.
Ich würde jedoch nicht anfangen, rohe
Servlet
Klassen zu schreiben . Die Arbeit, die sie leisten, ist sehr vorhersehbar und auf dem Kessel, was das Framework sehr gut macht. Glücklicherweise gibt es viele verfügbare, bewährte Kandidaten (in alphabetischer Reihenfolge): Apache Wicket , Java Server Faces , Spring, um nur einige zu nennen.quelle
Meiner Meinung nach gibt es bei Webanwendungen keinen großen Unterschied, wenn Sie sie unter dem Gesichtspunkt der Verantwortungszuweisung betrachten. Behalten Sie jedoch die Klarheit in der Ebene. Bewahren Sie alles, was nur für Präsentationszwecke bestimmt ist, in der Präsentationsebene auf, z. B. das Steuerelement und den Code, die für die Websteuerelemente spezifisch sind. Behalten Sie einfach Ihre Entitäten in der Geschäftsschicht und alle Funktionen (wie Hinzufügen, Bearbeiten, Löschen) usw. in der Geschäftsschicht. Sie werden jedoch in den Browser gerendert, um in der Präsentationsebene verarbeitet zu werden. Für .Net ist das ASP.NET MVC-Muster sehr gut, um die Ebenen getrennt zu halten. Schauen Sie sich das MVC-Muster an.
quelle
Ich habe das Federbein- Framework verwendet und finde es ziemlich einfach zu lernen. Bei Verwendung des Struts-Frameworks enthält jede Seite Ihrer Site die folgenden Elemente.
1) Eine Aktion, die verwendet wird, wird jedes Mal aufgerufen, wenn die HTML-Seite aktualisiert wird. Die Aktion sollte die Daten im Formular beim ersten Laden der Seite füllen und Interaktionen zwischen der Web-Benutzeroberfläche und der Geschäftsschicht verarbeiten. Wenn Sie die JSP-Seite zum Ändern eines veränderlichen Java-Objekts verwenden, sollte eine Kopie des Java-Objekts im Formular und nicht im Original gespeichert werden, damit die Originaldaten nur geändert werden, wenn der Benutzer die Seite speichert.
2) Das Formular, mit dem Daten zwischen der Aktion und der JSP-Seite übertragen werden. Dieses Objekt sollte aus einer Reihe von Gettern und Setzern für Attribute bestehen, auf die die JSP-Datei zugreifen muss. Das Formular verfügt auch über eine Methode zum Überprüfen von Daten, bevor diese beibehalten werden.
3) Eine JSP-Seite, die zum Rendern des endgültigen HTML-Codes der Seite verwendet wird. Die JSP-Seite ist eine Mischung aus HTML- und speziellen Struts-Tags, mit denen auf Daten im Formular zugegriffen und diese bearbeitet werden können. Obwohl Struts es Benutzern ermöglicht, Java-Code in JSP-Dateien einzufügen, sollten Sie diesbezüglich sehr vorsichtig sein, da dies das Lesen Ihres Codes erschwert. Java-Code in JSP-Dateien ist schwer zu debuggen und kann nicht Unit-getestet werden. Wenn Sie feststellen, dass Sie mehr als 4-5 Zeilen Java-Code in eine JSP-Datei schreiben, sollte der Code wahrscheinlich in die Aktion verschoben werden.
quelle
Die ausgezeichnete Antwort von BalusC deckt die meisten Muster für Webanwendungen ab.
Für einige Anwendungen ist möglicherweise Chain-of-Responsibility- Muster erforderlich
Anwendungsfall, um dieses Muster zu verwenden:
Wenn der Handler zum Verarbeiten einer Anforderung (Befehl) unbekannt ist und diese Anforderung an mehrere Objekte gesendet werden kann. Im Allgemeinen setzen Sie den Nachfolger auf Objekt. Wenn das aktuelle Objekt die Anforderung nicht verarbeiten oder die Anforderung teilweise verarbeiten kann, leiten Sie dieselbe Anforderung an das Nachfolgeobjekt weiter .
Nützliche SE-Fragen / Artikel:
Warum sollte ich jemals eine Verantwortungskette gegenüber einem Dekorateur verwenden?
Gemeinsame Verwendungen für die Verantwortungskette?
Chain-of-Responsibility-Muster von Oodesign
Verantwortungskette aus der Quellenherstellung
quelle