Wie ändert man das Design, so dass Entitäten keine Injektionen verwenden?

8

Ich habe gelesen und bin zu der Erkenntnis gekommen, dass Entitäten (Datenobjekte - für JPA oder Serialisierung) mit Injektionen in ihnen eine schlechte Idee sind. Hier ist mein aktuelles Design (alle geeigneten Felder haben Getter und Setter, und serialVersionUID , die ich aus Platzgründen weggebe).

Dies ist das übergeordnete Objekt, das der Kopf des Entitätszusammensetzungsgraphen ist. Dies ist das Objekt, das ich serialisiere.

%Vor%

AbstractPlane und seine Unterklassen sind nur einfache Klassen ohne Injektionen:

%Vor%

Im Gegensatz dazu benötigt jeder konkrete Fahrzeugtyp einen Manager, der ein bestimmtes Verhalten und auch eine bestimmte Form von Daten enthält:

%Vor%

Die CarxManager sind @Stateless Beans, die Operationen an den ihnen zugewiesenen Daten (den passenden CarxData ) ausführen. Sie selbst verwenden weiterhin Injektionen von vielen anderen Bohnen und sie sind alle Unterklassen von AbstractCarManager . Es gibt O (100) Autotypen und passende Manager.

Das Problem beim Serialisieren von State ist, dass das Serialisieren der Liste der abstrakten Autos mit den Injektionen in den Unterklassen nicht gut funktioniert. Ich bin auf der Suche nach einem Design, das die Injektion von der Datenspeicherung entkoppelt.

Meine vorherigen verwandten Fragen: Wie serialisiert man eine injizierte Bean? und Wie kann ich dem CDI-Container mitteilen, dass er aktiviert werden soll? "Eine Bohne?

    
Mark 06.09.2017, 04:13
quelle

4 Antworten

2

Eine Möglichkeit besteht darin, die Eigenschaft zu entfernen, damit sie von den Serialisierern nicht erkannt wird. Dies kann erreicht werden, indem es programmgesteuert wird.

%Vor%

Ich würde nicht dies als eine saubere Lösung betrachten, aber es sollte eine praktikable "Lösung" sein.

Auch die Verwendung von JPA's @Transient :

funktioniert möglicherweise %Vor%

Ich habe das nicht getestet, also könnte es nicht funktionieren.

    
Albert Bos 08.09.2017, 14:27
quelle
8

Sie können das Repository-Muster verwenden. Platzieren Sie Ihre Geschäftslogik in einen Service und injizieren Sie das Repository (das den Persistenzmechanismus abstrahiert) und den Manager in diesen Service. Das Repository blendet die Persistenzimplementierungsdetails aus dem Business-Service aus, und die Entitäten sind nur einfache POJOs.

Es würde ungefähr wie folgt aussehen: Foo wäre die ID der Entity-Leiste:

%Vor%

Siehe auch: Repository-Muster Schritt für Schritt Erläuterung , Ссылка . Einige Frameworks wie Spring Data JPA oder deltaspike implementieren bereits das Repository-Muster für Sie. Sie müssen lediglich eine Schnittstelle wie die folgende bereitstellen und die Implementierung im Hintergrund generieren:

%Vor%

Als Antwort auf Ihre Anfrage für weitere Details markieren Ich werde eine umgestaltete Lösung anbieten, weil das Beispiel in der Frage für mich wirklich keinen Sinn ergab und ziemlich viele Anti-Muster aufweist, die zu problematischer Software führen.

Um eine gute Lösung für das Problem zu finden, gibt es viele verschiedene Überlegungen, von denen viele sehr große Themen mit vielen Büchern über sie sind, aber ich werde mein Bestes versuchen, mein Denken basierend auf diesen zu illustrieren, um das Obige zu lösen Problem.

Und ich entschuldige mich, da ich keinen Zweifel daran habe, dass Sie viele davon kennen, aber ich werde aus Gründen der Klarheit begrenztes Wissen übernehmen.

Der erste Schritt bei der Lösung dieses Problems ist nicht der Code, aber über das Modell selbst wird modellgetriebene Entwicklung ausführlich in Eric Evans Buch behandelt, wie in den Kommentaren unten erwähnt. Das Modell sollte die Implementierung steuern und sollte auch auf seiner eigenen Ebene als Teil einer geschichteten Architektur bestehen und besteht aus Entitäten, Wertobjekten und Factories.

Modellgetriebene Entwicklung

In dem in der Frage gegebenen Modell haben wir etwas, das State genannt wird, das AbstractPlanes und AbstractCars enthält. Sie verwenden JPA, um den Status zu erhalten, der effektiv ein Aggregat Ihrer Flugzeuge und Autos ist. Erstens, irgendeinen Zustand in Software zu nennen, ist ein schlechter Geruch, weil so ziemlich alles einen Zustand hat, aber das, was wir hier haben, das Aggregat State macht noch weniger Sinn.

Wie unterscheidet sich State von anderen? Ist ein Auto Teil eines Staates und ein anderer Teil eines anderen Staates oder gehören alle Flugzeuge und Autos zu einer einzigen Instanz von Staat . Was ist die Beziehung zwischen Flugzeugen und Autos in diesem Szenario? Wie steht eine Liste von Flugzeugen und eine Liste von Fahrzeugen in Beziehung zu einer einzelnen State Einheit?

Wenn State tatsächlich ein Flughafen war und wir daran interessiert waren, wie viele Flugzeuge und Autos gerade auf dem Boden waren, dann könnte das das richtige Modell sein. Wenn State ein Flughafen wäre, hätte er einen Namen oder eine Identität wie seinen Flughafencode, aber nicht und so ...

... in diesem Fall scheint State ein Objekt zu sein, das als Annehmlichkeit benutzt wird, um auf das Objektmodell zuzugreifen. So treiben wir unser Modell effektiv durch Implementierungsüberlegungen an, wenn wir es andersherum machen und unsere Implementierung von unserem Modell leiten sollten.

Begriffe wie CarData sind auch aus dem gleichen Grund problematisch, wenn Sie eine Car-Entity erstellen und dann ein separates Objekt zum Speichern der Daten unordentlich und verwirrend ist.

Wenn das Modell nicht korrekt ist, führt dies zu einer Software, die bestenfalls durcheinander gebracht wird und im schlimmsten Fall völlig funktionsunfähig ist. Dies ist eine der größten Ursachen für fehlgeschlagene IT-Programme und je größer das Projekt, desto schwieriger ist es, diese Dinge richtig zu machen.

Überarbeitetes Modell

So verstehe ich aus dem Modell, dass wir Autos haben und wir Flugzeuge haben, deren Instanzen alle einzigartige Entitäten mit ihrer eigenen Identität sind. Sie scheinen für mich getrennte Dinge zu sein, und deshalb hat es keinen Sinn, sie in einem Aggregat zu halten.

%Vor%

Eine weitere Überlegung ist die Verwendung von abstrakten Klassen im Modell. Im Allgemeinen möchten wir das Prinzip der Bevorzugung von Kompositionen über die Vererbung anwenden , da Vererbung zu versteckten Verhaltensweisen führen und ein Modell schwer lesbar machen kann . Warum haben wir zum Beispiel einen PropelllerPlane und einen EnginePlane ? Sicher ist ein Propeller nur eine Art von Motor? Ich habe das Modell stark vereinfacht:

%Vor%

Die Ebene ist eine Entität mit eigenen Attributen und einer eigenen Identität. Es gibt keine Notwendigkeit, zusätzliche Klassen zu haben, die nichts in der realen Welt repräsentieren, nur um Attribute zu speichern.Das Engine-Objekt ist derzeit eine Enumeration, die den Motortyp in der Ebene darstellt:

%Vor%

Wenn der Motor selbst eine Identität erfordern würde, wie in realen Motorseriennummern und Dingen verfolgt werden, dann würden wir dies zu einem Objekt ändern. Aber wir möchten vielleicht nicht den Zugriff darauf zulassen, außer über eine Ebenenentitatinstanz. In diesem Fall wird die Ebene als aggregierter Stamm bekannt sein - das ist ein fortgeschrittenes Thema und ich würde Evans Buch für weitere Details zu Aggregaten empfehlen.

Das gleiche gilt für die Car-Entität.

%Vor%

Alles, was Sie benötigen, ist das, was in der Frage für die Basis Ihres Modells angegeben wurde. Ich habe dann ein paar Factory-Klassen erstellt, die mit der Erstellung von Instanzen dieser Entitäten umgehen:

%Vor%

Was wir hier auch tun, ist die Trennung von Bedenken, da nach dem Prinzip der einheitlichen Verantwortung jede Klasse nur eine Sache wirklich tun sollte.

Jetzt, da wir ein Modell haben, müssen wir wissen, wie wir damit umgehen können. In diesem Fall würden wir höchstwahrscheinlich bei Verwendung von JPA die Autos in einer Tabelle mit dem Namen Car and the Planes ebenfalls beibehalten. Wir würden den Zugriff auf diese persistenten Entitäten über Repositories, CarRepository und PlaneRespository ermöglichen.

Sie können dann Klassen namens services erstellen, die die Repositories (und alles, was Sie sonst noch benötigen) injizieren, um CRUD (Create Read Update Delete) -Operationen für die Instanzen von Autos und Flugzeugen durchzuführen und dies ist auch der Punkt, an dem Sie Ihr Geschäft anwenden können Logik zu diesen. Wie Ihre Methode:

%Vor%

Indem Sie Ihren Code auf diese Weise strukturieren, entkoppeln Sie das Modell (Entitäten und Wertobjekte) davon, wie sie persistent sind (Repositories), von den Diensten, die auf sie wirken, wie in Ihrer Frage erwähnt:

  

Ich suche nach einem Design, das die Injektion von der Datenspeicherung entkoppelt.

    
Justin.Cooke 13.09.2017 12:50
quelle
0

Was ist der Einstiegspunkt? Ist das eine Web-Anwendung, ein Rest-Service, ein Soap-Service oder ein Event-Scheduler?

Injection Frameworks trennen fast immer Daten und Service. Daten sind immer POJO und enthalten absolut keine Geschäftslogik. Angenommen, dies ist ein Ruhe-Service, werde ich Folgendes tun:

%Vor%     
maress 08.09.2017 16:04
quelle
0

Wenn Sie Ihren Fluss ändern könnten, könnten Sie vielleicht so etwas tun:

%Vor%

Ich habe einen inneren Dienst eingeführt, der auf Car1 funktioniert und den Car1Manager dafür verwendet. Ihre AbstractCar-Klasse verliert natürlich auch ihre Methode operate , weil Ihr Dienst von nun an damit fertig wird. Anstatt also car1.operate (i) aufzurufen, müssen Sie einen Anruf über den Dienst wie folgt tätigen:

%Vor%

Natürlich sollten Sie für alle anderen AbsractCar children eine ähnliche Funktionalität einführen (vielleicht sogar eine Abstraktion extrahieren, wie zum Beispiel AbsractCarInnerService, die operate -Methode oder eine Schnittstelle definieren würde, die dasselbe tun würde, wenn Sie nicht möchten Ich möchte keine anderen soliden Methoden darin. Allerdings ist diese Antwort immer noch irgendwie mit @ Justin Cooke Antwort verbunden und meiner Meinung nach sollten Sie auf jeden Fall die Muster überprüfen, die er in seinem Beitrag erwähnt.

    
pokemzok 14.09.2017 14:19
quelle