Best-Practice - Multi-Schicht-Architektur und DTOs
Nach der Lektüre einige der Q/Als hier auf stackoverflow, ich bin immer noch verwirrt über die korrekte Umsetzung der DTOs in meiner web-Anwendung. Meine aktuelle Umsetzung ist ein (Java EE basiert) multi-tier-Architektur (mit Ausdauer -, service-und Präsentation-layer), aber mit einer "common" - Paket durch alle Schichten, mit (unter anderem) domain-objecs. In diesem Fall sind die Ebenen kann man wirklich nicht als unabhängig betrachtet werden.
Ich bin Planung, um die zu entfernen common-Paket Schritt für Schritt, aber ich begegne verschiedenen Herausforderungen/Fragen:
- Übernehmen die Persistenz-Schicht würde eine Klasse verwenden myproject.die Persistenz.domain.UserEntity (eine JPA-basierte Einheit) zum speichern und laden von Daten in/aus der Datenbank. Um Daten anzuzeigen, die in der Sicht würde ich eine andere Klasse myproject.service.domain.Benutzer. Wo muss ich Sie konvertieren? Würde der service für die Nutzer sind verantwortlich für die Konvertierung zwischen den beiden Klassen? Würde das wirklich helfen zu verbessern die Kupplung?
- Wie sollte die Benutzer Klasse Aussehen? Sollte es enthalten nur Getter zu werden, unveränderlich sind? Wäre es nicht umständlich für die Ansichten zum Bearbeiten von existierenden Benutzern (erstellen Sie eine neue Benutzer, verwenden Sie die get-der bestehenden Benutzer Objekt etc.)?
- Sollte ich das gleiche DTO-Klassen (Benutzer) senden Sie eine Anfrage an den service zu ändern Sie einen vorhandenen Benutzer/einen neuen Benutzer erstellen oder sollte ich umsetzen, andere Klassen?
- Wäre das nicht der Präsentations-Schicht sehr abhängig von der service-Schicht, mit der alle DTOs in myproject.service.domain?
- Zu behandeln, wie meine eigenen Ausnahmen? Mein Aktueller Ansatz rethrows die meisten "schweren" Ausnahmen, bis Sie behandelt werden, von der Präsentations-Schicht (in der Regel sind Sie angemeldet, und der Benutzer wird darüber informiert, dass etwas schiefgelaufen ist). Auf der einen Seite habe ich das problem, dass ich hava wieder ein gemeinsames Paket. Auf der anderen Seite bin ich noch nicht sicher, dass diese können als "best practice". Irgendwelche Ideen?
Danke für alle Antworten.
- Ich werde die Abstimmung zu schließen, ist diese Frage off-topic, denn es ist eine Architektur und keine Programmierung questin.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Dass einige Pakete unter den verschiedenen Schichten ist nicht ungewöhnlich, jedoch ist es in der Regel nur für cross-cutting-concerns wie logging. Ihr Modell sollte nicht geteilt werden, die von unterschiedlichen Schichten, oder änderungen am Modell erfordern würde änderungen in allen Schichten. In der Regel, Ihr Modell einer niedrigeren Ebene, nahe an die Daten-Schicht (über -, unter-oder miteinander verflochten sind, je nach Ansatz).
Daten-Transfer-Objekte, wie Ihr name impliziert, sind einfache Klassen verwendet, um Daten zu übertragen. Als solche, Sie sind in der Regel verwendet, um die Kommunikation zwischen Ebenen, speziell, wenn Sie haben eine SOA-Architektur, die kommuniziert über Nachrichten und nicht Objekte. DTOs werden sollte, unveränderlich, seit Sie existieren lediglich für den Zweck der übertragung von Informationen, nicht zu ändern.
Ihre domain-Objekte sind eine Sache, Ihre DTOs sind eine andere Sache, und die Objekte, die Sie in Ihrem Präsentations-Schicht sind noch eine andere Sache. Jedoch, in kleinen Projekten kann es nicht sein, lohnt sich der Aufwand bei der Implementierung alle diese verschiedenen sets und konvertieren zwischen Ihnen. Das hängt nur von Ihren Anforderungen.
Sie entwerfen eine web-Anwendung, aber es kann helfen, Ihr design, um sich zu Fragen, "könnte ich wechsle meine web-Anwendung eine desktop-Anwendung? Mein service layer wirklich Ahnung von meiner Präsentation und Logik?". Das denken in diesen Bedingungen führt Sie hin zu einer besseren Architektur.
Auf Ihre Fragen:
Den service layer kennt seine Klassen (DTOs) und der Schicht darunter (sagen wir, Persistenz). Ja, der service ist verantwortlich für die übersetzung zwischen Beharrlichkeit und sich selbst.
Die Idee hinter DTOs ist, dass Sie nur verwenden Sie für die übertragung, so dass Operationen wie das erstellen eines neuen Benutzers sind nicht erforderlich. Für diese müssen Sie verschiedene Objekte.
Den service-Methoden möglicherweise express den Betrieb, die DTOs als seine Parameter die nur die Daten enthält. Eine weitere option ist die Verwendung der Befehle, die für die Bedienung und enthalten auch die DTOs. Dies ist sehr beliebt in SOA-Architekturen, wo Ihr die Dienstleistung kann ein bloßer Befehl Prozessor zum Beispiel mit einem einzigen
Execute
operation unter einerICommand
Schnittstelle als parameter hat (im Gegensatz zu einer operation pro Befehl).Ja, die Schicht über den service-layer abhängig. Das ist die Idee. Der Vorteil ist, dass nur diese Ebene ist auf die it angewiesen, keine oberen oder unteren Ebenen, so dass änderungen nur auf diese Ebene (im Gegensatz zu, was passiert, wenn Sie Ihre domain-Klassen aus jeder Schicht).
Jede Ebene kann Ihren eigenen Ausnahmen. Sie fließen von einer Schicht zur anderen, eingekapselt in die nächste Art von Ausnahme. Manchmal, Sie werden behandelt, indem eine Schicht, die etwas tun (Anmeldung, zum Beispiel) und vielleicht werfen Sie dann eine andere Ausnahme, daß eine Obere Ebene behandeln müssen. Andere Zeiten, Sie behandelt werden konnte und das problem gelöst werden könnte. Denken Sie z.B. ein problem mit der Datenbank verbinden. Es würde eine exception werfen. Sie könnte damit umgehen und entscheiden, zu wiederholen, nachdem ein zweiter und vielleicht dann gibt es Erfolg, so ist die Ausnahme würde nicht aufwärts fliessen. Sollte das auch fehlschlagen, wiederholen, wird die Ausnahme erneut geworfen, und es darf fließen, den ganzen Weg bis zu der Präsentations-Schicht, wo Sie ordnungsgemäß den Benutzer Benachrichtigen und ihn bitten, zu wiederholen Schicht.
Lose Kopplung ist in der Tat der empfehlenswerteste Weg zu gehen, das heißt, Sie werden am Ende mit riesigen, langweilig zu schreiben, zu schmerzhaft, zu pflegen Wandler auf Ihrer business-Logik. Ja, Sie gehören in die business-Logik: die Schicht zwischen DAOs und die Aussicht. Also die business-Schicht wird am Ende in Abhängigkeit von der DAO DTOs und der Blick DTOs. Und voller Konverter-Klassen, verdünnen Sie Ihren Blick auf die eigentliche business-Logik...
Wenn Sie Weg erhalten können mit unveränderlichen Blick DTOs, das ist toll. Eine Bibliothek, die Sie verwenden für die Serialisierung von Ihnen verlangen, Sie zu haben, setter obwohl. Oder finden Sie vielleicht, Sie einfacher zu bauen, wenn Sie spielen.
Habe ich Weg bekommen, nur fein mit den gleichen DTO-Klassen für beide die Aussicht und die DAOs. Es ist schlimm, aber ehrlich gesagt, habe ich nicht das Gefühl haben, dass das system mehr entkoppelt sonst, da die business-Logik, der wichtigste Teil, hat, hängt eh alles. Diese enge Kopplung ist vorgesehen für große Prägnanz, und es leichter gemacht, zu synchronisieren, anzeigen und DAO-Layer. Ich könnte noch Dinge, die spezifisch nur auf eine der Ebenen und nicht gesehen, in der anderen durch die Verwendung der Zusammensetzung.
Schließlich zu Ausnahmen. Es ist eine Verantwortung, der der äußersten Schicht, view-Schicht (der Controller, wenn Sie mit Feder), um Fehler abzufangen vermehrt aus den inneren Schichten werden es mit Ausnahmen, sei es mit speziellen DTO Felder. Dann ist diese äußerste Schicht der entscheiden muss, wenn Sie zu informieren Sie den Kunden über die Fehler, und wie. Die Tatsache ist, dass bis auf die innerste Schicht, Sie müssen unterscheiden zwischen den verschiedenen Arten von Fehlern, die die äußerste Schicht behandeln muss. Zum Beispiel, wenn etwas passiert in der DAO-Schicht, und die view-Schicht muss wissen, ob zur Rückgabe der 400 oder 500, die DAO-Schicht müssen die view-Schicht mit den erforderlichen Informationen, um zu entscheiden, welche zu benutzen ist, und diese Informationen werden übergeben zu müssen, durch alle intermediären Ebenen, die, sollten in der Lage sein zu geben, Ihre eigenen Fehler und Fehlertypen. Vermehrung eine IOException oder eine SQLException, um die äußerste Schicht ist nicht genug, die innere Schicht muss auch sagen, die äußere Schicht, wenn dies ist ein erwarteter Fehler ist oder nicht. Traurig, aber wahr.